• Добро пожаловать на Форум пользователей ПО АСКОН. Пожалуйста, авторизуйтесь.
 

Уважаемые пользователи,

Хотим проинформировать вас о режиме работы регистрации на нашем сайте.

Зарегистрироваться возможно в рабочие дни, с 8:00 до 20:00 (мск).

Если у вас возникнут вопросы или потребуется дополнительная информация, не стесняйтесь обращаться к нашей службе поддержки. Вы можете связаться с нами по указанным контактным данным на нашем сайте.

Благодарим вас за понимание и сотрудничество. Мы ценим ваше терпение и стремимся предоставить вам лучший опыт использования нашего сервиса.

С уважением,
Команда Ascon

Вызов COM объекта средствами Python

Автор Doom, 01.07.23, 23:42:38

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

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

Doom

Доброго,

Есть COM объект он зарегистрирован и отображается и вызывается на C# без каких либо проблем.
Он написал как x64 компонент и python 3.8.11 x64
Пытаюсь запустить так:

import win32com.client
# from win32com.client import Dispatch, GetActiveObject, gencache, constants

App = win32com.client.Dispatch('MyApp.Application')
App.Visible = True

constants= win32com.client.gencache.EnsureModule('{S1850913-S67A-ALM8-B261-11DF78ASDA12}', 0, 1, 0)
App = constants.Application(App)

выдает ошибку: com_error: (-2147221164, 'Класс не зарегистрирован', None, None)
что не так ?  :?:

Валерий Изранов

Цитата: Doom от 01.07.23, 23:42:38Он написал как x64 компонент и python 3.8.11 x64

А зачем ЭТО нужно вызывать?

Doom

Цитата: Валерий Изранов от 02.07.23, 06:46:31А зачем ЭТО нужно вызывать?

Ну а как Вы с ним собираетесь работать ?

Валерий Изранов

Цитата: Doom от 01.07.23, 23:42:38Есть COM объект
как то очень мало про него написано.

Doom

Цитата: Валерий Изранов от 02.07.23, 09:45:34как то очень мало про него написано.

Объект написан мною и представляет из себя exe приложение - вовремя COM вызова она запускается и хранит результаты работы в переменных для того что передать следующему приложению которое ее и вызывает.

Я пробывал записывать объекты в файл/сериализовать - не чего из этого не вышло. 

Валерий Изранов

Помочь сможет Михаил88 из числа  лучших специалистов по python на Форуме.
Я думаю, он сюда заглянет.

Doom

Попробовал с другими приложениями - какие то работают какие то нет и таже ошибка..

import pythoncom, win32com.client

fdm = pythoncom.LoadTypeLib(r"C:\for test\com\myappapi.tlb")
downloads_stat = None

for index in range(0, fdm.GetTypeInfoCount()):
    type_name = fdm.GetDocumentation(index)[0]

    if type_name == 'Application':
        type_iid = fdm.GetTypeInfo(index).GetTypeAttr().iid
        downloads_stat = win32com.client.Dispatch(type_iid)
        break

downloads_stat.BuildListOfDownloads(True, True)
print(downloads_stat.Download(0).Url)

нашел способы я так понимаю для непосредственного вызова

CoGetClassObject (ctypes)

но там код такой кудрявый что можно на месяцок застрять..

Doom

Скорее всего что то не то со стороны создаваемого com компонента - попробовал штатными средствами создать com  объект на VS C# - все работает.

Мб как то создать обертку и ее подписать (не понимаю как подписать библиотеки написанные не под .Net (есть лайфхаки не требующие подписи, но как отреагирует защита системы - вопрос))

Как создать автоматически обертку ?
нашел этот инструмент но там вышли ошибки что не все объекты обработаны и после не хочет регистрироваться
https://learn.microsoft.com/en-us/dotnet/framework/tools/tlbimp-exe-type-library-importer

Здесь уже речь не идет о моем com объекте, а хотя бы с установленными программами разобраться а потом уже обдумывать..


На vs когда добавляю ссылку на объект то в сборке можно указать локальное копирование и генерируется MyApp.Aplication.Interop но не во всех случаях в моем эта кнопка не активна ..

Или я что то путаю?

Doom

Цитата: Doom от 01.07.23, 23:42:38com_error: (-2147221164, 'Класс не зарегистрирован', None, None)

ошибка которая указывает на:

  • Объекты доступа к данным (DAO) не зарегистрированы должным образом.
  • Отсутствует одна или несколько ссылок.
  • Недопустимая ссылка на базу данных утилиты.
  • У вас нет необходимых разрешений для необходимых библиотек.
  • Имеется поврежденный файл мастера.

Добавил я в окружение пути программы - ошибку надо конкретней выдавать а не так обобщенно, ищи свищи в тысячах долин..



Вират Лакх

Цитата: Doom от 01.07.23, 23:42:38Доброго,

Есть COM объект он зарегистрирован и отображается и вызывается на C# без каких либо проблем.
Он написал как x64 компонент и python 3.8.11 x64
Пытаюсь запустить так:

import win32com.client
# from win32com.client import Dispatch, GetActiveObject, gencache, constants

App = win32com.client.Dispatch('MyApp.Application')
App.Visible = True

constants= win32com.client.gencache.EnsureModule('{S1850913-S67A-ALM8-B261-11DF78ASDA12}', 0, 1, 0)
App = constants.Application(App)

выдает ошибку: com_error: (-2147221164, 'Класс не зарегистрирован', None, None)
что не так ?  :?:
На какой строке кода выдаёт указанную ошибку? Должно быть на последней.
У Вас подозрительные последние две строки.
У вас App - это интерфейс приложения. Интерфейс может получиться "разный". А потом что вы делаете? EnsureModule - это генерация библиотеки типов, а не константы; лучше это делать перед Dispatch.
Если вы импортируете константы, то в самом коротком виде это можно записать так (EnsureModule заполняет constants, если есть чем) на примере Excel:
from win32com.client import gencache, constants
gencache.EnsureModule('{00020813-0000-0000-C000-000000000046}', 0, 1, 9)
print(constants.xlAscending)
Почитайте, как работает Dispatch. Он сначала пытается приконнектиться к запущенному приложению pythoncom.connect('MyApp.Application'), если не получилось, создаёт объект. В любом случае пытается обернуть полученный интерфейс по библиотеке типов. Если готового модуля нет, то он пытается получить инфу от приложения и создать модуль. Например, для компаса API7 прокатывает Dispatch('Kompas.Application.7') без явного указания модуля, а для API5 - нет, поэтому приходится самому генерить библиотеку типов через EnsureModule и ему явно указывать, во что обернуть полученный интерфейс:
API5 = gencache.EnsureModule('{0422828C-F174-495E-AC5D-D31014DBBE87}', 0, 1, 0)
app5 = Dispatch('Kompas.Application.5', None, API5.KompasObject.CLSID)
Если надо просто прицепиться к приложению без универсальных ходов на все случаи жизни, которые делает Dispatch, то:
KompasObject = API5.KompasObject(pythoncom.connect('Kompas.Application.5')) # Сами оборачиваем, приводим к нужному интерфейсу.
Короче, разберитесь, где у вас константы, а где библиотека типов.
+ Благодарностей: 1

Doom

#10
У приложений где выходит эта ошибка com_error: (-2147221164, 'Класс не зарегистрирован',.. если запустить приложение и затем выполнить
App = win32com.client.Dispatch('MyApp.Application')
Все работает без ошибок..
Видимо антивирусная система виндовс или еще что то мешает работе Dispatch в создании объекта..
С одними приложениями работает все как часы - с другими нереальный тупняк..

Doom

#11
Цитата: Вират Лакх от 03.07.23, 10:11:13Почитайте, как работает Dispatch.

Вы можете скинуть документацию или ссылку ?
то что в сети - урезанный материал и там почти не чего и не написано.

http://timgolden.me.uk/pywin32-docs/PyIDispatch.html


Doom

Цитата: Вират Лакх от 03.07.23, 10:11:13Интерфейс может получиться "разный". А потом что вы делаете?

Да, так и есть - разный, второй видимо создается для привидения активных объектов к типу и далее вызов соответствующих методов/свойств
Но я делаю иначе

TypeObj = gencache.EnsureModule(...

# получаем интерфейс чертежа
A_Doc = App.ActiveDocument
A_Doc2 = TypeObj.DrawingDocument(A_Doc)

Цитата: Вират Лакх от 03.07.23, 10:11:13Если вы импортируете константы, то в самом коротком виде это можно записать так (EnsureModule заполняет constants, если есть чем) на примере Excel:

Да константы заполняются, но я не пойму 2 ситуации с ней:

1) почему нельзя вывести список констант ?
print(dir(constants))
2) Почему то нарушается иерархия констант
например:
const_1.const_2.const_3

так не работает - constants.const_1.const_2.const_3
а работает только так - constants.const_3

Вират Лакх

#13
Цитата: Doom от 04.07.23, 20:38:36Вы можете скинуть документацию или ссылку ?
то что в сети - урезанный материал и там почти не чего и не написано.
\Python311\Lib\site-packages\win32com\client\__init__.py - тут написан def Dispatch
Цитата: Doom от 04.07.23, 22:50:54Но я делаю иначе
Так и надо.
Цитата: Doom от 04.07.23, 22:50:541) почему нельзя вывести список констант ?
Там словарь/словари внутри объекта. В самом простом виде:
print(constants.__dicts__)
Или:
for k, v  in constants.__dicts__[0].items():
    print(k, v)
Цитата: Doom от 04.07.23, 22:50:542) Почему то нарушается иерархия констант
Что за иерархия? Константы собираются в одну кучу - список словарей.
Можно не пользоваться from win32com.client import constants, а подключать самому. Например, в компасе константы находятся в отдельной библиотеке типов:
consts = gencache.EnsureModule('{2CAF168C-7961-4B90-9DA2-701419BEEFE3}', 0, 1, 0).constants
+ Благодарностей: 1

Doom

#14
Цитата: Вират Лакх от 03.07.23, 10:11:13EnsureModule - это генерация библиотеки типов
Очень удобно, нашел сгенерированные модуль и библиотеку в %Temp%\gen_py.


А есть такая возможность для НЕ зарегистрированных в системе COM объекта в виде просто dll файла который лежит в папке приложения?
Например в C# - просто добавил ссылку на нее и все работает, а как в Python ее использовать? Зарегистрировать ее нельзя..
Эта dll написана на C++, если в случае Net - можно было бы пересобрать, но с плюсами не хватит скила у меня.


Встретилось приложение которая имеет модуль управления в виде .pyd файла, но он не хочет подключаться к Python не как.
Например при pythonx32 -не является приложением win32
при pythonx64 - Не удалось загрузить файл или сборку ... либо одну из их зависимостей.

Пробовал и так

import clr
import sys
import os

sys.path.append(r"C:\Program Files\MyApp\python")
clr.AddReference('MyApp')

import MyApp

Хотя макросы Python работают из самого приложения а внешне - не как не хочет. Я так и не нашел инструментов для разборки pyd файлов и полагаю их не будет.

Хотя указано мульти разрядность

Вират Лакх

Может что-то отсюда вам поможет:
# https://docs.python.org/3/library/ctypes.html

from ctypes import *

lib_1 = cdll.msvcrt
lib_1.printf(b"From dll with love!\n")

lib_2 = cdll.LoadLibrary(r"C:\Windows\System32\msvcrt.dll")
lib_2.printf(b"From dll with love!\n")

lib_3 = CDLL(r"C:\Windows\System32\msvcrt.dll")
lib_3.printf(b"From dll with love!\n")

lib_4 = windll.LoadLibrary(r"C:\Windows\System32\msvcrt.dll")
lib_4.printf(b"From dll with love!\n")

lib_5 = WinDLL(r"C:\Windows\System32\msvcrt.dll")
lib_5.printf(b"From dll with love!\n")

lib_6 = oledll.LoadLibrary(r"C:\Windows\System32\msvcrt.dll")
lib_6.printf(b"From dll with love!\n")

lib_7 = OleDLL(r"C:\Windows\System32\msvcrt.dll")
lib_7.printf(b"From dll with love!\n")
+ Благодарностей: 1

Doom

Да так работает..

Иногда при генерировании модуля - встречаются комментарии в коде, да и наглядность выше. Попробую пересоздать библиотеку для регистрации в системе.

Doom

#17
В общем нашел способ..

Не как не могу извлечь из под программы список временных окружений создаваемых на время сессии программы..

Тут получаем список которые берутся из системы, но там нет списка инициализируемой программой.
import os

for name, value in os.environ.items():
    print("{0}: {1}".format(name, value))

Так если задать то получаем соответствующее значение.

import os
os.environ["DEBUSSY"] = "1"

for name, value in os.environ.items():
    if "DEBUSSY" in name:
        print("{0}: {1}".format(name, value))

Пример как программа внутри себя инициализирует их.

Dim python As String = "C:\Python38-32"
            'список всех путей где программа будет искать модули
            Dim Python_Path1 As String = "C:\Python38-32\DLLs;"
            Python_Path1 += "C:\Python38-32\Lib;"
            Python_Path1 += "C:\Python38-32\Lib\curses;"
            Python_Path1 += "C:\Python38-32\Lib\site-packages;"
            Python_Path1 += "C:\Python38-32\Lib\site-packages\win32;"
            Python_Path1 += "C:\Python38-32\Lib\site-packages\win32\lib;"
            Python_Path1 += "C:\Python38-32\Lib\site-packages\win32\libs;"
            Python_Path1 += "C:\Python38-32\Lib\site-packages\win32com;"
            Python_Path1 += "C:\Python38-32\Lib\site-packages\win32com\client;"
            Python_Path1 += "C:\Python38-32\Lib\site-packages\Pythonwin;"
            Python_Path1 += DyrectoryPluginsUses

            Environment.SetEnvironmentVariable("PATH", python, EnvironmentVariableTarget.Process)
            Environment.SetEnvironmentVariable("PYTHONHOME", python, EnvironmentVariableTarget.Process)
            Environment.SetEnvironmentVariable("PYTHONPATH", Python_Path1, EnvironmentVariableTarget.Process)

Вот как получить этот список PATH/PYTHONHOME/PYTHONPATH ? (пытался в hex представлении искать в файлах программы, но что то пошло не так)

Doom

Суть в том что бы извлечь все зависимости при том что имена файлов не уникальны.
По фото выше видно что просто список линков отображается а из каких каталогов они взяты не понятно.

Модуль Python из под которого хочу получить список - работает как дочерняя программа, а окружение видимо создает головная программа и наверно так список нельзя получить..

Есть ли способ через WinApi по указанному процессу ?

Doom

Цитата: Doom от 16.07.23, 14:29:53Встретилось приложение которая имеет модуль управления в виде .pyd файла, но он не хочет подключаться к Python не как.

Могут ли в таком варианте быть функции экспортными (external) и локальными ?

Если запускать сгенерированной программой скрипт внутри этой программы он заработает а если пытаться внешними средствами запустить скрипт то он упирается в отсутствие методов или свойств ?

...