Дождаться полного окна Компас 3D.

Автор Student2025, 24.12.25, 12:08:26

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

Student2025

Добрый динь!

В API Компас 3D есть метод ksGetHWindow - но он спешит с результатом. Выдает дескриптор окнf, а оно еще не прорисовано. Этот эффект усиливается если компьютер мягко говоря слабенький. И от получения дескриптора до полной прорисовки может варьироваться от 0.1 до 3 минут! А если еще и создаются библиотеки то они тоже могут увеличивать время запуска Компас 3D! Мне нужно точно знать что главное окно Компаса 3D полностью прорисовано! И я использую средства WinAPI, что то нашел но выходит ошибка:

def get_hwnds_for_pid(pid):
   
    GetWindowThreadProcessId = ctypes.windll.user32.GetWindowThreadProcessId
    GetWindowThreadProcessId.argtypes = [ctypes.wintypes.HWND, ctypes.POINTER(ctypes.wintypes.DWORD)]
    GetWindowThreadProcessId.restype = ctypes.wintypes.DWORD
   
   
    EnumWindows = ctypes.windll.user32.EnumWindows
    # Определяем тип функции обратного вызова (callback)
    EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.wintypes.BOOL, ctypes.wintypes.HWND, ctypes.wintypes.LPARAM)
   
   
   
    def callback(hwnd, lpParam):
        # LPARAM_value - это указатель на наш список hwnds
        py_obj = ctypes.cast(lpParam, ctypes.POINTER(ctypes.py_object)).contents
        hwnds = py_obj.value

        dw_process_id = ctypes.wintypes.DWORD()
       
        # _, found_pid = win32process.GetWindowThreadProcessId(hwnd)
       
        GetWindowThreadProcessId(hwnd, ctypes.byref(dw_process_id))
        found_pid = dw_process_id.value

        if found_pid == pid:
            hwnds.append(hwnd)
        return True
   
   
    # EnumWindows = ctypes.windll.user32.EnumWindows
   
    hwnds = []
    # win32gui.EnumWindows(callback, hwnds)
   
    lpEnumFunc = EnumWindowsProc(callback)
   
    # EnumWindows(callback, hwnds)
    # EnumWindows(lpEnumFunc, ctypes.py_object(hwnds))

    py_obj_hwnds = ctypes.py_object(hwnds)
    # lpParam = ctypes.cast(ctypes.pointer(py_obj_hwnds), ctypes.wintypes.LPARAM)
   
    # get real memory address of py_object
    addr = ctypes.addressof(py_obj_hwnds)

    # convert to LPARAM
    lparam = ctypes.wintypes.LPARAM(addr)
   
   
    EnumWindows(lpEnumFunc, lparam)
   
    return hwnds
 


Проблема скрыта в локальной функции callback

p3452

Ничего не понял из Вашего "кода", но:
1. "Процесс" имеет "флаг" завершения, отслеживайте его.
2. "Старт" Компаса имеет "подчиненные" процессы...

Student2025

#2
Цитата: p3452 от 24.12.25, 13:10:10"Процесс" имеет "флаг" завершения, отслеживайте его.
Например?
В моем понимании флаг один - это получение списка процессов (если их несколько) - поиск видимых окон - получение title.
Другие флаги по монитору ресурсов - такое себе точность.
Так же смотрел через файловую активность, но это уход в локальность, а меня больше интересует универсальность.

Цитата: p3452 от 24.12.25, 13:10:10"Старт" Компаса имеет "подчиненные" процессы...
Есть пример?

С тем кодом что то странное происходит - как будто ломается WinAPI и даже перезагрузка как IDE так и Компас 3D не спасает а только перезагрузка компьютера.  :bang:


Soultaker

Работаю с плагинами и такой проблемы нет.

Student2025

Цитата: Soultaker от 24.12.25, 14:34:19Работаю с плагинами и такой проблемы нет.

Это конечно все хорошо, но хочется универсальности. Один раз написал и пользуешься везде и на долго. 

Student2025

Цитата: p3452 от 24.12.25, 13:10:10Ничего не понял из Вашего "кода", но:

WinAPI - основа основ и так с ним незнаючи, нельзя! 88))

p3452

Можно и через "голый" WinAPI (на крайняк), но в данном случае - в .Net есть бибилиотека System.Diagnostics.Process, в ней есть все необходимое...
А в сочетании с асинхронным режимом, возможности возрастают многократно.

p3452

Например, как вариант, так, стартуем процесс:
Process process = new Process();
if (process != null) {
    process.StartInfo.FileName = psCom;
    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.Arguments = psArg;
    if (psCom.Contains(".exe ") || psCom.Contains(".com ") || psCom.Contains(".bat ")) {
        process.StartInfo.UseShellExecute = false;
    }
    else {
        process.StartInfo.UseShellExecute = true;
    }
    try {
        bool flag = process.Start();
    }
    catch {
        //...       
    }
}

Student2025

#9
p3452, это какое то жестяное дичь!

Все способы штатные - спешат!
Dim idle As Boolean = process.WaitForInputIdle()
Dim tmp As IntPtr = process.MainWindowHandle
MessageBox.Show("ok")

p3452

Student2025, Вы сами то себя понимаете?

Soultaker


Student2025

#12
p3452, зачем натянули сову на ногу ?  :o

Зачем столько излишних проверок городить ? Ваш код просто запускает а мне надо дождаться окна (все методы System.Diagnostics.Process, не сработали как мне надо по ожиданию окна).

p3452

Student2025, судя по Вашим словам Вы не осилили ЭТИ два десятка строк код...
Цитата: Student2025 от 25.12.25, 15:13:47все методы System.Diagnostics.Process, не сработали как мне надо по ожиданию окна)
- Ваши "хотелки", это ваши "хотелки"!

Student2025

#14
p3452 ну знаете ли, могли просто имена нужных объектов написать, а не так вот из далека. Вы бы еще написали в библиотеке
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.dll есть все что нужно..  >:(
Или на диске C: все найдете.

Пока вы занимались вредительством я уже все сделал.
Ошибка в преобразовании списка..

def get_hwnds_for_pid(pid, user32):
   
    hwnds = []
   
    # Определяем тип callback'а для EnumWindows
    EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.wintypes.BOOL, ctypes.wintypes.HWND, ctypes.wintypes.LPARAM)

    # Объявляем функции
    user32.EnumWindows.argtypes = [EnumWindowsProc, ctypes.wintypes.LPARAM]
    user32.EnumWindows.restype = ctypes.wintypes.BOOL
   
    user32.GetWindowThreadProcessId.argtypes = [ctypes.wintypes.HWND, ctypes.POINTER(ctypes.wintypes.DWORD)]
    user32.GetWindowThreadProcessId.restype = ctypes.wintypes.DWORD  # возвращает thread ID


    def callback(hwnd, lparam):
       
        window_pid = ctypes.wintypes.DWORD()
       
        user32.GetWindowThreadProcessId(hwnd, ctypes.byref(window_pid))
       
        if window_pid.value == pid:
            hwnds.append(hwnd)
           
        return True  # продолжить перечисление

    # Создаём callback с нужной сигнатурой
    enum_proc = EnumWindowsProc(callback)

    # Вызываем EnumWindows
    user32.EnumWindows(enum_proc, 0)  # lparam = 0, т.к. используем замыкание
   
    # в иструкции ищем описание ошибок объекта
    # error = ctypes.get_last_error()
    # if error != 0:
    #     print(f"Ошибка 1: {error}")
    #     return None

    return hwnds


Если нужно можно и проверку включить по загрузке кнопок которые связаны с библиотекой и они тоже могут грузится далеко не сразу поэтому ищем хендл нужной кнопки. 
Я бы не назвал что это "хотелки" а скорее обычная рядовая задача.