Доступ к нескольким работающим копиям CATIA (VB)

Программирование для CATIA.

Доступ к нескольким работающим копиям CATIA (VB)

Сообщение Wireless_Fidelity » 20 янв 2011 11:35

Здравствуйте.

Как многие знают, CATIA возможно автоматизировать с помощью любого языка, поддерживающего COM-объекты. При этом программисту доступен функционал, предлагаемый CATIA Automation API. Получение доступа к работающей CATIA не является проблемой. Однако, ситуация меняется в худшую сторону, когда на машине запущены несколько копий CATIA, а хочется иметь возможность автоматизировать каждую из них. Как же это сделать?

Вопрос этот довольно старый, но ответа на него я не нашёл. Хотя, как мне кажется, в нём могут быть заинтересованы многие. Существует ряд соображений, из которых следует, что автоматизация отдельных копий CATIA через объектную модель COM невозможна из-за особенностей её реализации самой CATIA. Но подтвердить или опровергнуть данное утверждение не удалось. Надеюсь, что это станет возможным с вашей помощью.
В качестве отправной точки в поиске решения предлагаю код, написанный на VB.NET (VS 2005), который призван отыскать все работающие копии CATIA и вернуть связанные с ними COM объекты. Код снабжён комментариями на английском языке, но, уверен, переводить их не требуется:
 Код :
Код: Выделить всё
   
            Public Declare Auto Function CreateBindCtx Lib "ole32.dll" ( _
            ByVal reserved As Integer, _
            ByRef ppbc As System.Runtime.InteropServices.ComTypes.IBindCtx) As Integer

    Public Declare Auto Function BindMoniker Lib "ole32.dll" ( _
            ByVal pmk As System.Runtime.InteropServices.ComTypes.IMoniker, _
            ByVal grfOpt As Integer, _
            ByVal iidResult As String, _
            ByRef ppvResult As Object) As Integer

    '====================================================================================
    '   We try to access multiple CATIA instances by searching for their monikers
    ''====================================================================================
    Private Function GetCATIAInstances() As Object

        ' we create IBindCtx instance with CreateBindCtx WinAPI function
        Dim HRESULT As Long
        Dim objCtx As System.Runtime.InteropServices.ComTypes.IBindCtx = Nothing
        HRESULT = CreateBindCtx(0, objCtx)

        ' enlist all items in Running Object Table (ROT)
        Dim objROT As System.Runtime.InteropServices.ComTypes.IRunningObjectTable
        objCtx.GetRunningObjectTable(objROT)

        ' extract monikers from ROT
        Dim RunningMonikers As System.Runtime.InteropServices.ComTypes.IEnumMoniker
        objROT.EnumRunning(RunningMonikers)


        ' declare variables
        Dim strDisplayName As String
        Dim strCLSID As String

        Dim ptrFetchedMonikers As System.IntPtr
        Dim ArrMonikers(10) As System.Runtime.InteropServices.ComTypes.IMoniker

        Dim COMObject As Object
        Dim ArrCATIAInstances() As Object

        Dim CATGUID As System.Guid
        Dim iRunningStatus As Integer

        Dim iCATInstance As Integer = 0


        ' convert INFITF.Application class into Type class. This will be used later.
        Dim CATType As Type = GetType(INFITF.Application)


        ' iRunningStatus = objROT.IsRunning(monikercontainer(0))

        ' We're going to cycle through all monikers found in ROT
        ' Now we want to reset numeration inside of RunningMonikers collection
        RunningMonikers.Reset()

        ' Start working with monikers.
        ' We ask Next method to put one moniker into ArrMonikers array
        While (RunningMonikers.Next(1, ArrMonikers, ptrFetchedMonikers) = 0)

            ' get display name of current moniker
            ArrMonikers(0).GetDisplayName(objCtx, Nothing, strDisplayName)

            ' check if this name matches with CATIA display name (predefined)
            If (strDisplayName = "!{87FD6F40-E252-11D5-8040-0010B5FA1031}") Then

                '--------------------------------------------------
                ' We found moniker that represents CATIA instance.
                '--------------------------------------------------

                ' What we need is to get GUID of Application interface
                ' This can be done in several ways:
                '   create GUID using ID provided with INFITF type library
                CATGUID = New System.Guid(INFITF.IID_InfInterfaces.IID_Application)

                '   use GUID method of Type class (this was converted from INFITF.Application)
                CATGUID = CType(CATType.GUID, System.Guid)


                ' Now we want to get COM objects associated with monikers
                ' We try to do it differently:
                '   try to do this using GetObject method of Running Object Table
                objROT.GetObject(ArrMonikers(0), COMObject)

                '   we bind moniker to object:
                'ArrMonikers(0).BindToObject(objCtx, Nothing, CATGUID, COMObject)   ' THIS CAUSES ERROR

                '   finally, we use BindMoniker WinAPI function:
                'BindMoniker(ArrMonikers(0), 0, INFITF.IID_InfInterfaces.IID_Application, COMObject)    ' THIS RETURNS NULL IN COMObject


                ' if we've succeeded in retrieving COM object from moniker, we add it to result array
                If Not (COMObject Is Nothing) Then
                    ReDim Preserve ArrCATIAInstances(iCATInstance)
                    ArrCATIAInstances(iCATInstance) = COMObject
                    iCATInstance = iCATInstance + 1
                End If
            End If

        End While

        ' we return array of instance
        GetCATIAInstances = ArrCATIAInstances

    End Function


Описанная выше функция должна возвращать массив объектов, представляющих работающие копии 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.
Аватара пользователя
Wireless_Fidelity
Активный участник
Активный участник
 
Сообщения: 394
Зарегистрирован: 10 апр 2010 00:11

Re: Доступ к нескольким работающим копиям CATIA (VB)

Сообщение booSter » 20 янв 2011 13:02

- В старой крепости надо было его через трубу брать.
© Сухов / "Белое Солнце Пустыни"


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

Я бы пошёл другим путём. Если запущенная копия КАТИИ хочет быть доступной персонально (через уникальный COM-объект типа Application), то ей (копии) самой надо об этом позаботится "зарегистрировавшись" в специально запущеном для этой цели нами же написанном COM-сервере (некий COM-компонент оформленный виде EXE-модуля и реализующий коллекцию объектов Application).
Сделаешь доброе дело за деньги - скажут спасибо,
Сделаешь бесплатно - сядут на шею...
©пёрто
Аватара пользователя
booSter
Moderator
 
Сообщения: 227
Images: 15
Зарегистрирован: 09 фев 2008 16:48
Откуда: Minsk

Re: Доступ к нескольким работающим копиям CATIA (VB)

Сообщение Wireless_Fidelity » 20 янв 2011 14:19

booSter, спасибо за ответ.

Идея очень интересная. Но получается, что для её реализации необходимо заставить копию CATIA самостоятельно зарегистрироваться на нашем COM-сервере, ибо зарегистрировать её "извне" мы, насколько я понимаю этот процесс, не можем. Выходит, что нужно запускать какую-то процедуру регистрации при инициализации очередной копии CATIA, а это значит нужно использовать CAA. И ещё вопрос, сможет ли CAA зарегистрировать копию кати на COM-сервере...
Аватара пользователя
Wireless_Fidelity
Активный участник
Активный участник
 
Сообщения: 394
Зарегистрирован: 10 апр 2010 00:11

Re: Доступ к нескольким работающим копиям CATIA (VB)

Сообщение booSter » 20 янв 2011 14:51

У модуля CNEXT.exe есть параметры командной строки (запустите CNEXT.exe -h)

Изображение

CAA - сможет зарегистрировать копию на сервере.
Сделаешь доброе дело за деньги - скажут спасибо,
Сделаешь бесплатно - сядут на шею...
©пёрто
Аватара пользователя
booSter
Moderator
 
Сообщения: 227
Images: 15
Зарегистрирован: 09 фев 2008 16:48
Откуда: Minsk

Re: Доступ к нескольким работающим копиям CATIA (VB)

Сообщение Wireless_Fidelity » 20 янв 2011 15:49

booSter, спасибо, обязательно изучу.
Аватара пользователя
Wireless_Fidelity
Активный участник
Активный участник
 
Сообщения: 394
Зарегистрирован: 10 апр 2010 00:11

Re: Доступ к нескольким работающим копиям CATIA (VB)

Сообщение Artem » 21 янв 2011 21:13

Сразу скажу что ком технологию знаю как пользователь и про ее внутренности ничего не знаю - нашел видимо подобный код на VB6:
 код :
Код: Выделить всё
'===============Form code - drop list box on form========
Private Sub Form_Load()
   EnumRot List1
  ' Class_Initialize
End Sub

Private Sub Form_Resize()
   If WindowState = vbMinimized Then Exit Sub
   List1.Move 0, 0, ScaleWidth, ScaleHeight
End Sub

'============================================
' And here is its implementation - ROT enumeration
'============== mEnumRot.bas==================
Option Explicit

Type Guid
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(0 To 7) As Byte
End Type

Public Declare Function CLSIDFromString Lib "ole32.dll" (ByVal lpsz As String, pCLSID As Guid) As Long
Public Declare Function CLSIDFromProgID Lib "ole32.dll" (ByVal sProgID As String, pCLSID As Any) As Long
Public Declare Function StringFromGUID2 Lib "ole32.dll" (ByRef rGuid As Any, ByVal lpsz As String, ByVal cbMax As Long) As Long

Private Declare Function lstrlenW Lib "kernel32" (ByVal lpString As Long) As Long
Private Declare Function WideCharToMultiByte Lib "kernel32" _
    (ByVal codepage As Long, ByVal dwFlags As Long, _
    lpWideCharStr As Any, ByVal cchWideChar As Long, _
    lpMultiByteStr As Any, ByVal cchMultiByte As Long, _
    ByVal lpDefaultChar As String, _
    ByVal lpUsedDefaultChar As Long) As Long

Private Declare Function GetRunningObjectTable Lib "ole32.dll" (ByVal dwReserved As Long, pROT As Long) As Long
Private Declare Function CreateBindCtx Lib "ole32.dll" (ByVal dwReserved As Long, pBindCtx As Long) As Long
Private Declare Sub CoTaskMemFree Lib "ole32.dll" (ByVal pv As Long)

Const ItemMoniker = "{00000304-0000-0000-C000-000000000046}"
Const FileMoniker = "{00000303-0000-0000-C000-000000000046}"

Public Sub EnumRot(lb As ListBox)
   Dim pROT As Long, pEnumMoniker As Long, pMoniker As Long, pBindCtx As Long
   Dim ret As Long, nCount As Long
   Dim sName As String, sClass As String, sType As String
   Dim pName As Long
   Dim uid As Guid
   lb.Clear
   ret = GetRunningObjectTable(0, pROT)
   ret = CreateBindCtx(0, pBindCtx)
   CallInterface pROT, IROT_EnumRunning, 1, VarPtr(pEnumMoniker)
  ' MsgBox pMoniker
   While CallInterface(pEnumMoniker, IEnumMoniker_Next, 3, 1, VarPtr(pMoniker), VarPtr(nCount)) = 0
  ' MsgBox pMoniker
        CallInterface pMoniker, IMoniker_GetClassID, 1, VarPtr(uid)
        CallInterface pMoniker, IMoniker_GetDisplayName, 3, pBindCtx, 0, VarPtr(pName)
        Dim dd As Long
       
        CallInterface pROT, IROT_GetObject, 2, pMoniker, VarPtr(dd)
        sClass = String(255, 0)
        ret = StringFromGUID2(uid, sClass, 255)
        sClass = TrimNULL(StrConv(sClass, vbFromUnicode))
        Select Case sClass
           Case FileMoniker: sType = "File moniker"
           Case ItemMoniker: sType = "Item moniker"
           Case Else: sType = "Unknown moniker"
        End Select
       
        lb.AddItem sType & vbTab & StrFromPtrW(pName) & vbTab & CStr(dd)
        CallInterface pMoniker, IUnk_Release, 0
        CoTaskMemFree pName
   Wend
   CallInterface pEnumMoniker, IUnk_Release, 0
   CallInterface pBindCtx, IUnk_Release, 0
   CallInterface pROT, IUnk_Release, 0
End Sub

Function StrFromPtrW(ByVal lpszW As Long, Optional nSize As Long = 0) As String
   Dim s As String, bTrim As Boolean
   If nSize = 0 Then
      nSize = lstrlenW(lpszW) * 2
      bTrim = True
   End If
   s = String(nSize, Chr$(0))
   WideCharToMultiByte 0, &H0, ByVal lpszW, -1, ByVal s, Len(s), &H0, &H0
   If bTrim Then s = TrimNULL(s)
   StrFromPtrW = s
End Function

Function TrimNULL(ByVal str As String) As String
    If InStr(str, Chr$(0)) > 0& Then
        TrimNULL = Left$(str, InStr(str, Chr$(0)) - 1&)
    Else
        TrimNULL = str
    End If
End Function

'IEnumMoniker interface methodts in VTABLE order
Public Enum VTABLE_IEnumMoniker
'IUnknown methods 0 to 2
   IEnumMoniker_Next = 3  ' Gets the next items in the enumeration sequence.
   IEnumMoniker_Skip = 4  ' Attempts to skip over the next celt elements in the enumeration sequence.
   IEnumMoniker_Reset = 5 ' Resets the enumeration sequence to the beginning.
   IEnumMoniker_Clone = 6 ' Creates a copy of the current state of enumeration.
End Enum

'IMoniker interface methodts in VTABLE order
Public Enum VTABLE_IMoniker
'IUnknown methods 0 to 2
'IPersist Method
   IMoniker_GetClassID = 3           ' Returns the class identifier (CLSID) for the component object.
'IPersistStream Methods
   IMoniker_IsDirty = 4              ' Checks the object for changes since it was last saved.
   IMoniker_Load = 5                 ' Initializes an object from the stream where it was previously saved.
   IMoniker_Save = 6                 ' Saves an object into the specified stream and indicates whether the object should reset its dirty flag.
   IMoniker_GetSizeMax = 7           ' Return the size in bytes of the stream needed to save the object.
'IMoniker Methods
   IMoniker_BindToObject = 8         ' Binds to the object named by the moniker.
   IMoniker_BindToStorage = 9        ' Binds to the object's storage.
   IMoniker_Reduce = 10              ' Reduces the moniker to simplest form.
   IMoniker_ComposeWith = 11         ' Composes with another moniker.
   IMoniker_Enum = 12                ' Enumerates component monikers.
   IMoniker_IsEqual = 13             ' Compares with another moniker.
   IMoniker_Hash = 14                ' Returns a hash value.
   IMoniker_IsRunning = 15           ' Checks whether object is running.
   IMoniker_GetTimeOfLastChange = 16 ' Returns time the object was last changed.
   IMoniker_Inverse = 17             ' Returns the inverse of the moniker.
   IMoniker_CommonPrefixWith = 18    ' Finds the prefix that the moniker has in common with another moniker.
   IMoniker_RelativePathTo = 19      ' Constructs a relative moniker between the moniker and another.
   IMoniker_GetDisplayName = 20      ' Returns the display name.
   IMoniker_ParseDisplayName = 21    ' Converts a display name into a moniker.
   IMoniker_IsSystemMoniker = 22     ' Checks whether moniker is one of the system-supplied types.
End Enum

Private Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long

Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long)
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Public Declare Function VarPtr Lib "msvbvm60" (var As Any) As Long

Private Const GMEM_FIXED As Long = &H0
Private Const asmPUSH_imm32 As Byte = &H68
Private Const asmRET_imm16 As Byte = &HC2
Private Const asmRET_16 As Long = &H10C2&
Private Const asmCALL_rel32 As Byte = &HE8

Public Function CallInterface(ByVal pInterface As Long, ByVal FuncOrdinal As Long, ByVal ParamsCount As Long, Optional ByVal p1 As Long = 0, Optional ByVal p2 As Long = 0, Optional ByVal p3 As Long = 0, Optional ByVal p4 As Long = 0, Optional ByVal p5 As Long = 0, Optional ByVal p6 As Long = 0, Optional ByVal p7 As Long = 0, Optional ByVal p8 As Long = 0, Optional ByVal p9 As Long = 0, Optional ByVal p10 As Long = 0) As Long
  Dim i As Long, t As Long
  Dim hGlobal As Long, hGlobalOffset As Long
 
  If ParamsCount < 0 Then Err.Raise 5 'invalid call
  If pInterface = 0 Then Err.Raise 5
 
  '5 bytes for each parameter
  '5 bytes - PUSH this
  '5 bytes - call member function
  '3 bytes - ret 0x0010, pop CallWindowProc
  '1 byte - dword align.
   
  hGlobal = GlobalAlloc(GMEM_FIXED, 4 * ParamsCount + 5 + 5 + 3 + 1)
  If hGlobal = 0 Then Err.Raise 7 'insuff. memory
  hGlobalOffset = hGlobal
 
  'push parameters
  If ParamsCount > 0 Then
    t = VarPtr(p1)
    For i = ParamsCount - 1 To 0 Step -1
      CopyMemory ByVal hGlobalOffset, asmPUSH_imm32, 1
      hGlobalOffset = hGlobalOffset + 1
      CopyMemory ByVal hGlobalOffset, ByVal t + i * 4, 4
      hGlobalOffset = hGlobalOffset + 4
    Next
  End If
 
 'First member of any interface - this. Assign...
  CopyMemory ByVal hGlobalOffset, asmPUSH_imm32, 1
  hGlobalOffset = hGlobalOffset + 1
  CopyMemory ByVal hGlobalOffset, pInterface, 4
  hGlobalOffset = hGlobalOffset + 4
 
  'Call IFace Function by its ordinal
  CopyMemory ByVal hGlobalOffset, asmCALL_rel32, 1
  hGlobalOffset = hGlobalOffset + 1
  CopyMemory t, ByVal pInterface, 4    'dereference: find vTable
  CopyMemory t, ByVal t + FuncOrdinal * 4, 4 'Function offset in vTable, dereference
  CopyMemory ByVal hGlobalOffset, t - hGlobalOffset - 4, 4
  hGlobalOffset = hGlobalOffset + 4

  'all interfaces are stdcall, so forget about stack clearing
  CopyMemory ByVal hGlobalOffset, asmRET_16, 4       'ret 0x0010
 
  'finally, run asm code prepared
  CallInterface = CallWindowProc(hGlobal, 0, 0, 0, 0)
  GlobalFree hGlobal
End Function




Меня вот что смутило - VBA родной замечательно взаимодействует со своей родной сессией это раз и если одну из сессий закрыть наше приложение без проблем переключится на вторую сессию это два......Вот тут показана реализация GetObject http://www.compdoc.ru/prog/cpp/com/ch3/ch38.shtml (Сдесь же где то вроде натыкался на реализацию BindToObject) - я чего думаю - может MkParseDisplayName всегда возвращает моникер от первого встреченного обьекта и соответственно до следующих не доходит..(Хотя код воспринимаю чисто интуитивно и если глупость сказал извиняюсь) соответственно может покопать в корректный запуск BindToObject?
animae scrinium servitus
Аватара пользователя
Artem
Активный участник
Активный участник
 
Сообщения: 387
Зарегистрирован: 14 сен 2007 07:14

Re: Доступ к нескольким работающим копиям CATIA (VB)

Сообщение Wireless_Fidelity » 22 янв 2011 02:14

booSter, посмотрел ключи запуска CATIA. /regserver и /unregserver, как следуют из документации, отвечают за работу OLE сервера (импорт документов различного типа между приложениями), а не COM. Действительно, что добавляй флаг regserver, что убирай, всё равно при нескольких запущенных копиях CATIA находится ровно один COM объект.


Artem, спасибо за ответ. К сожалению, другие копии трогать и закрывать категорически не хочется. Катийный VBA это какой-то странный зверь, совсем не похожий на Excel или тот же Visual Studio. Собственно, у него даже расширение .catvba. И совершенно не ясно, как запущенная копия VBA получает доступ к "своей" копии CATIA. Значит, факт подлежит изучению....

Ссылку на GetObject я уже раньше смотрел, но не углублялся в текст. Теперь, видимо, придётся :)
Именно в направлении корректного запуска BindToObject я и копаю, хотя в том же коде из ссылки он используется совершенно не так, как я предполагал.
Аватара пользователя
Wireless_Fidelity
Активный участник
Активный участник
 
Сообщения: 394
Зарегистрирован: 10 апр 2010 00:11

Re: Доступ к нескольким работающим копиям CATIA (VB)

Сообщение Artem » 25 янв 2011 17:57

1)Про VBA
 Код :
Код: Выделить всё
'VBA -форма TFrm,List1- listbox,CommandButton1
Private Declare Sub GetMem4 Lib "msvbvm60.dll" (ByVal pSrc As Long, ByVal pDest As Long)
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes&)
Private Declare Sub MoveMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal dwLength As Long)
Private Declare Sub PutMem4 Lib "msvbvm60" (ByVal Destination As Any, ByVal Value As Any)
Private Transfer_CATIA As Object
Private Function PtrToObj(ByVal lPtr As Long) As Object
Dim oUnk As Object
   MoveMemory oUnk, lPtr, 4&
   Set PtrToObj = oUnk
   MoveMemory oUnk, 0&, 4&
End Function

Private Function ObjPtr2(obj As Object) As Long
 Dim lpObj As Long
CopyMemory lpObj, obj, 4
ObjPtr2 = lpObj
End Function


Private Sub CommandButton1_Click()
 Dim a1 As Long
 TFrm.List1.AddItem CStr(ObjPtr(CATIA.Application))
 'TFrm.List1.AddItem CStr(VarPtr(ObjPtr(CATIA.Application)))
 TFrm.List1.AddItem CStr(VarPtr(CATIA.Application))
  TFrm.List1.AddItem "------"
 
 Set Transfer_CATIA = CATIA.Application
 TFrm.List1.AddItem CStr(ObjPtr(Transfer_CATIA))
 'TFrm.List1.AddItem CStr(VarPtr(ObjPtr(Transfer_CATIA)))
 Call GetMem4(VarPtr(Transfer_CATIA), VarPtr(a1))
  TFrm.List1.AddItem a1
  TFrm.List1.AddItem "------"
 
  Dim vv As Object
Set vv = PtrToObj(a1)
Call GetMem4(VarPtr(vv), VarPtr(a1))
TFrm.List1.AddItem a1
  Dim a2 As Long
  Call GetMem4(a1, VarPtr(a2))

  TFrm.List1.AddItem "!!!!"
  TFrm.List1.AddItem a2
  TFrm.List1.AddItem "/////"
End Sub


Вот это код на VBA позволяет копировать обьект уже установленный SETом на катьку в пустой обьект там же безо всякого сета...Учитывая что я смогу запустить VBA проект и выцепить данные и адреса оттуда автоматом, пытался копировать их по аналогии в свой проект - вылетает зараза - смещение наверное надо добавлять? :dash1:
2) Про запущенные процессы я имел ввиду не закрыть а может как нибудь залочить/"скрыть" процесс к которому подцепляется наш обьект, захватить второй а затем разлочить сразу его - смена приоритета как мертвому припарка, приостановка -вешает мою программу (Avir Task managerом делал)...Как в скрытые добавить не нашел, но тоже думаю не поможет
3)BindObjectом получил обьект от всех приложений офиса
Private Const IID_IUnknown As String = "{00000000-0000-0000-C000-000000000046}"
Private Const IID_IDispatch As String = "{00020400-0000-0000-C000-000000000046}"
- с помощью вот этого, но эти интерфейсы не помогли в случае с катькой - что в отношении IID_IUnknown достаточно странно учитывая что getobject хотябы на одну сессию катьки, но все же возвращает обьект с этим интерфейсом - BindObject -ни одного (так же не возвращали ничего и родные
Private Const IID_ICATIA As String = "{87fd6f40-e252-11d5-8040-0010b5fa1031}" -r19sp8
Private Const IID_ICATIAPRODUCT As String = "{86BC0A02-8C01-11d1-B109-0000F81EB4C6}" и т.д.)..соответсвенно можно не копать в этом направлении - не поможет(хотя может какой-нибудь волшебный интерфейс позволит достучаться...врядли я думаю)....Если че получится пиши-наверное остался только способ уважаемого бустера ((
animae scrinium servitus
Аватара пользователя
Artem
Активный участник
Активный участник
 
Сообщения: 387
Зарегистрирован: 14 сен 2007 07:14

Re: Доступ к нескольким работающим копиям CATIA (VB)

Сообщение Wireless_Fidelity » 25 янв 2011 19:46

Artem, спасибо огромное.

По 1), как я помню, у каждого процесса (в т.ч. и VBA) своё адресное пространство. Поэтому даже если получить адрес в VBA, чёрт его знает, как этим адресом пользоваться в другой программе-процессе.

По 3) я пытался ещё получать IID_IApplication, но также безрезультатно.

Пойду долбить способ №2, с процессами.
Аватара пользователя
Wireless_Fidelity
Активный участник
Активный участник
 
Сообщения: 394
Зарегистрирован: 10 апр 2010 00:11

Re: Доступ к нескольким работающим копиям CATIA (VB)

Сообщение Artem » 26 янв 2011 09:29

1)В свое время получалось вместо одной весьма полезной внутренней функции катьки засунуть весьма безполезный мессадж "hello word" - как раз оперированием оперативкой-поэтому и подумал про этот путь. Я вот тоже думаю, что getmem putmem vatptr и т.д. оперируют адресным пространством внутри самого приложения. Ну а если добавить его адрес, как смещение? Учитывая, что далеко не факт, что и после этого все заработает -копать так глубоко неохота. Может кто теоретически подкованный подскажет, хотябы гипотетически - этот путь рабочий? Тупой вопрос абсолютно не разбирающегося человека, но все же - ком сервис же внешнее "приложение" для нашего в VBA? если это так, то где то в созданном dim obj as object - должна хранится абсолютная ссылка на этот самый сервис, до нее бы дойти и скопировать в object нашего приложения...
2) Опять же может кто разбирающийся в ком технологии и процессах сэкономит время...к сожалению рядом со мной таковых нет.
4)Если в конкретной задаче требуется взаимодействие нескольких сессий можно воспользоваться совмещением тех же студий(интерфейс) +sendmessage (запуск макроса, вызов и управление командами катьки, частично получение данных)+собственно запускаемый макрос делающий основную работу. Данные передавать через файл или ту же оперативку.
animae scrinium servitus
Аватара пользователя
Artem
Активный участник
Активный участник
 
Сообщения: 387
Зарегистрирован: 14 сен 2007 07:14

Re: Доступ к нескольким работающим копиям CATIA (VB)

Сообщение Wireless_Fidelity » 26 янв 2011 10:58

1) Согласен. С этим вопросом нужно на форум тру-кодеров идти.

4) Я вот сейчас с SendMessage реализую эту задачу и могу сказать, что, как и ожидалось, такое решение не стабильное и малофункциональное :-( Но хоть какой-то минимум возможностей всё-таки предоставляет...
Аватара пользователя
Wireless_Fidelity
Активный участник
Активный участник
 
Сообщения: 394
Зарегистрирован: 10 апр 2010 00:11


Вернуться в CAA-RADE

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2