Как многие знают, CATIA возможно автоматизировать с помощью любого языка, поддерживающего COM-объекты. При этом программисту доступен функционал, предлагаемый CATIA Automation API. Получение доступа к работающей CATIA не является проблемой. Однако, ситуация меняется в худшую сторону, когда на машине запущены несколько копий CATIA, а хочется иметь возможность автоматизировать каждую из них. Как же это сделать?
Вопрос этот довольно старый, но ответа на него я не нашёл. Хотя, как мне кажется, в нём могут быть заинтересованы многие. Существует ряд соображений, из которых следует, что автоматизация отдельных копий CATIA через объектную модель COM невозможна из-за особенностей её реализации самой CATIA. Но подтвердить или опровергнуть данное утверждение не удалось. Надеюсь, что это станет возможным с вашей помощью.
В качестве отправной точки в поиске решения предлагаю код, написанный на VB.NET (VS 2005), который призван отыскать все работающие копии CATIA и вернуть связанные с ними COM объекты. Код снабжён комментариями на английском языке, но, уверен, переводить их не требуется:
Код :
Описанная выше функция должна возвращать массив объектов, представляющих работающие копии CATIA. Вызов функции производится следующим образом:
- Код: Выделить всё
Dim ArrCATInstances() as Object
ArrCATInstances = GetCATIAInstances()
Сразу отмечу, что нижеследующие размышления совершенно не претендуют на точность описания устройства объектной модели COM. Более того, я уверен, что в нём имеются ошибки. Именно для того, чтобы кто-либо указал мне на них, я и привожу своё видение ситуации.
Итак, что работает не так. Когда мы имеем две копии CATIA, метод GetObject объекта RunningObjectTable возвращает нам один и тот же объект для различных "моникеров" (решил оставить понятие без перевода, как в MSDN). Следует отметить, что BindMoniker и особенно BindToObject кажутся более подходящими для поставленной задачи, но их вызов вызывает ошибку.
Что есть "моникер"? Если кратко, то это объект, который содержит информацию, позволяющую однозначно определить COM-объект. Поэтому, условно говоря, если у нас есть моникер, то мы имеем возможность найти определяемый им объект COM.
Как работают CATIA и другие "большие" программы в контексте COM? Понятное дело, здесь всё непросто, но что нам действительно важно, так это, что они представляют собой так называемые "COM-серверы" (COM-servers), которые предоставляют стороннему программисту доступ к определённому функционалу. В момент своего запуска сервер должен регистрировать себя в Running Object Table (Таблице Выполняемых Объектов, ROT), специальном месте, в котором хранятся данные о запущенных объектах. В случае, когда мы запускаем вторую копию работающего приложения, эта копия также должна зарегистрироваться в ROT.
Однако, на практике оказывается, что это не всегда так. К примеру, как говорит нам MSDN, офисные приложения Word, Access (в отличие от PowerPoint, кстати) не регистрируют свои вторые (и последующие) копии в ROT. Так что "короткого" пути получения доступа к COM объектам этих копий напрямую из ROT нет. Тем не менее, загруженные в эти офисные приложения документы также регистрируются в ROT, поэтому, зная их имена, можно получить доступ сначала к ним, а затем уже к "родительским" объектам, то есть к офисным приложениям.
Примерно в соответствии с этими соображениями работает функция GetObject. Для получения доступа к конкретной копии программы Excel необходимо передать ей имя класса приложения, а также имя открытого документа:
Dim ExcelInstance as Object
ExcelInstance = GetObject("C:\MyDocs\Workbook.xls","Excel.Application")
Что плохого в этом подходе?
1. Необходимо знать точное имя документов, загруженных в копии программы. Если в какую-то копию или копии документы не загружены, то возникают дополнительные проблемы.
2. Для CATIA доступ по именам документов не работает.
Теперь применим всё вышесказанное к CATIA. Как мне кажется, она не регистрирует свои копии в ROT. Поэтому в случае с двумя запущенными копиями для двух разных моникеров возвращается один и тот же объект. Но тогда непонятно, почему же моникеров всё же два, а не один.
Далее. Не смотря на то, что доступ с использованием имени открытого катийного документа ("C:\MyDocs\SamplePart.CATPart") через GetObject не работает, эти документы появляются в ROT и имеют соответствующие им моникеры. Более того, objROT.GetObject для этих моникеров даже возвращает какие-то объекты, но совершенно непонятно, как ими пользоваться. Предположения о том, что объекты должны иметь класс, соответствующий катийным Document или Window, не подтвердились, поскольку обращение к специфическим для этих классов свойствам и методам не приносит результата и вызывает ошибку.
Прошу помощи в решении данной задачи. Буду благодарен за любую информацию как по конкретным строчкам размещённого выше кода, так и по особенностям работы нескольких копий приложения с точки зрения COM.