Try to get all names of program windows to pull Revit to the foreground

Hey guys,

I have following code from Win32 Python: Getting all window titles | Johannes Sasongko's (abandoned) blog :

import ctypes
 
EnumWindows = ctypes.windll.user32.EnumWindows
EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
GetWindowText = ctypes.windll.user32.GetWindowTextW
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
IsWindowVisible = ctypes.windll.user32.IsWindowVisible
 
titles = []
val = ""
def foreach_window(hwnd, lParam):
    if IsWindowVisible(hwnd):
        length = GetWindowTextLength(hwnd)
        buff = ctypes.create_unicode_buffer(length + 1)
        GetWindowText(hwnd, buff, length + 1)
        titles.append(buff.value)
        val = buff.value
    return True
EnumWindows(EnumWindowsProc(foreach_window), 0)
 
OUT = titles

In CPython3 it works just fine, but in IronPython the list is empty. Does anybody know how I can get this to work in IronPython?

Thanks in advance

What is the error you are seeing? Or is it just an empty list returned and nothing else? Do the intermediate outputs return valid items? If you remove the Title = does it run correctly?

Hi @jacob.small

I get no error just no result in IronPython:

Here the result in CPython3:

Certainly a case of CPython being an easier fit than IronPython… Why not use the CPython version?

What are the results of the intermediate variables before the Titles variable in each engine?

Because I want to use it in Revit 2021 :smiley: I just tried it in Revit 2023 and CPython3.

This is what I get, when I print every variable:

code:

import ctypes
 
EnumWindows = ctypes.windll.user32.EnumWindows
EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
GetWindowText = ctypes.windll.user32.GetWindowTextW
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
IsWindowVisible = ctypes.windll.user32.IsWindowVisible
 
titles = []
def foreach_window(hwnd, lParam):
    if IsWindowVisible(hwnd):
        length = GetWindowTextLength(hwnd)
        print(length)
        buff = ctypes.create_unicode_buffer(length + 1)
        print(buff)
        GetWindowText(hwnd, buff, length + 1)
        print(buff)
        print(buff.value)
        titles.append(buff.value)
    return True
EnumWindows(EnumWindowsProc(foreach_window), 0)

print(titles)

OUT = titles

console CPython3:

Python Script: []
Python Script: 0
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: 
Python Script: 0
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: 
Python Script: 0
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: 
Python Script: 13
Python Script: <ctypes.c_wchar_Array_14 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_14 object at 0x000001FC3EF24DC0>
Python Script: Python Script
Python Script: 6
Python Script: <ctypes.c_wchar_Array_7 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_7 object at 0x000001FC3EF24DC0>
Python Script: Dynamo
Python Script: 68
Python Script: <ctypes.c_wchar_Array_69 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_69 object at 0x000001FC3EF24DC0>
Python Script: Autodesk Revit 2023.1 - [gjgfj.rvt - Zeichenansicht: 090_TITELBLATT]
Python Script: 96
Python Script: <ctypes.c_wchar_Array_97 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_97 object at 0x000001FC3EF24DC0>
Python Script: Try to get all names of program windows to pull Revit to the foreground - Dynamo - Google Chrome
Python Script: 51
Python Script: <ctypes.c_wchar_Array_52 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_52 object at 0x000001FC3EF24DC0>
Python Script: Posteingang - leonard.moelders@zueblin.de - Outlook
Python Script: 38
Python Script: <ctypes.c_wchar_Array_39 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_39 object at 0x000001FC3EF24DC0>
Python Script: Giannis und Michaela | Microsoft Teams
Python Script: 0
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: 
Python Script: 0
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: 
Python Script: 43
Python Script: <ctypes.c_wchar_Array_44 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_44 object at 0x000001FC3EF24DC0>
Python Script: 096b151e-74ab-476f-9448-9733dae7020dMonitor
Python Script: 21
Python Script: <ctypes.c_wchar_Array_22 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_22 object at 0x000001FC3EF24DC0>
Python Script: Unbenannt ‎- Paint 3D
Python Script: 8
Python Script: <ctypes.c_wchar_Array_9 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_9 object at 0x000001FC3EF24DC0>
Python Script: Paint 3D
Python Script: 7
Python Script: <ctypes.c_wchar_Array_8 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_8 object at 0x000001FC3EF24DC0>
Python Script: Rechner
Python Script: 0
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: 
Python Script: 7
Python Script: <ctypes.c_wchar_Array_8 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_8 object at 0x000001FC3EF24DC0>
Python Script: Rechner
Python Script: 0
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: 
Python Script: 10
Python Script: <ctypes.c_wchar_Array_11 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_11 object at 0x000001FC3EF24DC0>
Python Script: MainWindow
Python Script: 0
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: 
Python Script: 0
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: 
Python Script: 0
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: 
Python Script: 0
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: 
Python Script: 0
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: 
Python Script: 32
Python Script: <ctypes.c_wchar_Array_33 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_33 object at 0x000001FC3EF24DC0>
Python Script: Microsoft Text Input Application
Python Script: 0
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: 
Python Script: 45
Python Script: <ctypes.c_wchar_Array_46 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_46 object at 0x000001FC3EF24DC0>
Python Script: FindWindows.py - VS Code - Visual Studio Code
Python Script: 0
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_1 object at 0x000001FC3EF24DC0>
Python Script: 
Python Script: 15
Python Script: <ctypes.c_wchar_Array_16 object at 0x000001FC3EF24DC0>
Python Script: <ctypes.c_wchar_Array_16 object at 0x000001FC3EF24DC0>
Python Script: Program Manager
Python Script: ['', '', '', 'Python Script', 'Dynamo', 'Autodesk Revit 2023.1 - [gjgfj.rvt - Zeichenansicht: 090_TITELBLATT]', 'Try to get all names of program windows to pull Revit to the foreground - Dynamo - Google Chrome', 'Posteingang - leonard.moelders@zueblin.de - Outlook', 'Giannis und Michaela | Microsoft Teams', '', '', '096b151e-74ab-476f-9448-9733dae7020dMonitor', 'Unbenannt \u200e- Paint 3D', 'Paint 3D', 'Rechner', '', 'Rechner', '', 'MainWindow', '', '', '', '', '', 'Microsoft Text Input Application', '', 'FindWindows.py - VS Code - Visual Studio Code', '', 'Program Manager']

console IronPython:

Python Script: []

EDIT:

I made further investigations and I think I found the problem:

in CPython3 my platform is win32:

but in IronPython:

Now this could be the reason why I get no results in IronPython as this quote says:

ctypes exports the cdll , and on Windows windll and oledll objects, for loading dynamic link libraries.

So I think in IronPython the ctypes library has no windll and therefore I don’t get any results.

I this logical?

EDIT#2:

Hmm but I can access windll:

More likely it’s because CPython is running down at the C level of your system, where the core components of your computer run (below windows), while the IronPython is running in the .net environment (above windows). As such the two will differ in terms of outcome/flexibility.

I’ll see what I can do with this today.

1 Like

Looks like you’ll need to directly set the callback function as noted here:

Hmm still does not work in IronPython. In CPython3 its still working:

Code:

import sys
sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib')
import ctypes
 
EnumWindows = ctypes.windll.user32.EnumWindows
EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
GetWindowText = ctypes.windll.user32.GetWindowTextW
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
IsWindowVisible = ctypes.windll.user32.IsWindowVisible
 
titles = []

def foreach_window(hwnd, lParam):
    if IsWindowVisible(hwnd):
        length = GetWindowTextLength(hwnd)
        buff = ctypes.create_unicode_buffer(length + 1)
        GetWindowText(hwnd, buff, length + 1)
        titles.append(buff.value)
    return True
    
foreach_window = EnumWindowsProc(foreach_window)
EnumWindows(foreach_window, 0)
 
OUT = titles

Result CPython3:

Result IronPython:

EDIT#1:

Whats also interesting is the fact that it does not find any visible windows in IronPython. When I dismiss the if condition it results in a list of empty strings:

EDIT#2:

Does anybody know how I can access win32gui, win32process and win32con? Maybe via pywin32, but how do I install it for Dynamo’s IronPython 2.7? (Revit 2021)

I don’t see a callback function as noted on the blog I linked before.

The func foreach_window is the callback function.

For comparison:

Or am I overseeing something here? :thinking:

Hello,
you can try this

import sys
import clr
import System
from System.Diagnostics import Process

import ctypes
import time

ptrB = Process.GetCurrentProcess().MainWindowHandle

ctypes.windll.user32.SetActiveWindow(ptrB)
ctypes.windll.user32.SetForegroundWindow(ptrB)

OUT = ptrB

but sometimes does not work :thinking:

2 Likes

I owe you one <3

I edited your code little to be shure, that revit gets pulled to the foreground:

import sys
import clr
import System
from System.Diagnostics import Process

import ctypes
import time

all = Process.GetProcesses()
for a in all:
	if "Revit" in a.MainWindowTitle:
		mwt_revit = a.MainWindowHandle
		
	
ctypes.windll.user32.SetActiveWindow(mwt_revit)
ctypes.windll.user32.SetForegroundWindow(mwt_revit)

OUT = mwt_revit

Works like a charm now. In the meantime I kinda solved my problem with a workaround by making a TaskDialog that gets pulled to the foreground (as I know the title of the window as I choose it by myself), but your solution is way better in my opinion.

Thank you two @jacob.small and @c.poupin for helping me on this topic.

2 Likes