GetObject и VB6 ActiveX exe

В справке по GetObject VB6 говорится: «Можно» t использовать GetObject для получения ссылки на класс, созданный с помощью Visual Basic »(самое последнее предложение!). Мой графический интерфейс VB6 предоставляет объекты как ActiveX exe, которыми могут манипулировать другие компоненты. Я хочу, чтобы другие компоненты подключались к уже работающему графическому интерфейсу, а не запускали новый экземпляр exe. Я обнаружил, что использование GetObject действительно работает, если вы используете этот синтаксис:

Set myobj = GetObject("", "ProjectName.ClassName")

Меня беспокоит, что в справке написано, что это не должно работать, хотя я провел довольно много тестов и пока не обнаружил никаких проблем. Любые эксперты в области COM, которые могут сказать мне, столкнусь ли я с проблемами в будущем? И я все равно буду в порядке с CreateObject?

Параметры ActiveX exe: пул потоков только с одним потоком. Класс имеет экземпляры MultiUse. Возможно, этих настроек достаточно, чтобы CreateObject в любом случае не запускал новый экземпляр exe. Это правильно?


person MarkJ    schedule 27.05.2009    source источник


Ответы (2)


Документация запутанная, но правильная. Страница MSDN, на которую вы ссылаетесь, помогает объяснить, почему ваш GetObject вызов не вызывает ошибки:

Если путь [первый аргумент] представляет собой строку нулевой длины (""), GetObject возвращает новый экземпляр объекта указанного типа. Если аргумент имени пути опущен, GetObject возвращает текущий активный объект указанного типа. Если объект указанного типа не существует, возникает ошибка.

Это тонко, но подразумевается, что

GetObject "", "ProjectName.ClassName

фактически эквивалентен

CreateObject "ProjectName.ClassName"

То есть передача пустой строки в первый параметр GetObject заставляет его работать точно так же, как CreateObject, что означает, что он создаст новый экземпляр класса, а не вернет ссылку на уже- запущенный экземпляр.

Возвращаясь к отрывку из MSDN, в нем упоминается, что полное отсутствие первого аргумента для GetObject приведет к тому, что GetObject вернет ссылку на уже запущенный экземпляр, если он существует. Такой вызов мог бы выглядеть так:

GetObject , "ProjectName.ClassName" 'Note nothing at all is passed for the first argument'

Однако, если вы попытаетесь это сделать, вы сразу получите ошибку времени выполнения. Это вариант использования, на который ссылается документация, когда говорится, что GetObject не работает с классами, созданными с помощью VB6.

Причина, по которой это не работает, заключается в том, как GetObject творит свою магию. Когда первый параметр опущен, он пытается вернуть существующий экземпляр объекта, обращаясь к таблице запущенных объектов (ROT), таблице поиска для всей машины, которая содержит запущенные COM-объекты. Проблема в том, что объекты должны быть явно зарегистрированы в таблице запущенных объектов процессом, который их создает, чтобы они были доступны другим процессам - среда выполнения VB6 не регистрирует классы ActiveX EXE в ROT, поэтому GetObject не имеет возможности получить ссылку на уже запущенный экземпляр.

person Mike Spross    schedule 27.05.2009
comment
Прекрасный ответ, спасибо. Я всегда говорю людям RT * M, так что это вкус моего собственного лекарства! GetObject (, ProjectName.ClassName) вызывает ошибку 429, компонент ActiveX не может создать объект. Я предполагаю, что на самом деле настройки моего проекта и класса предотвращают создание нескольких экземпляров EXE. - person MarkJ; 28.05.2009

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

Уловка состоит в том, чтобы помнить, что в ActiveX EXE его можно настроить так, чтобы был запущен только один экземпляр БИБЛИОТЕКИ. Верно, что вы не можете достичь и просто перехватить данный экземпляр класса через границу процесса. Однако ActiveX EXE можно настроить так, чтобы ГЛОБАЛЬНЫЕ переменные были доступны ЛЮБОМУ экземпляру классов.

Как именно это сделать, становится немного сложнее. Вы можете использовать ActiveX EXE как обычный EXE, главное отличие состоит в том, что вам НЕОБХОДИМО использовать Sub Main. Вы также можете проверить, работает ли он автономно или нет. Теперь я предполагаю, что это относится к приложению MarkJ.

В этом случае вам нужно создать класс приложения и настроить его так, чтобы при его создании (с помощью Class_Initialize) он заполнялся текущими запущенными экземплярами форм и коллекций.

Я настоятельно рекомендую вам создать ActiveX DLL (не EXE), в которой нет ничего, кроме классов, которые можно реализовать как интерфейсы. Вместо того, чтобы идти

'Class ThisGUIApp
Public MainForm as Form

Вы создаете интерфейс, который имеет все свойства и методы, необходимые для доступа к элементам основной формы. Тогда вы идете

'Class ThisGUIApp
Public MainForm as IMainForm

Private Sub Class_Initialize
  Set MainForm = frmMyMainForm
End Sub

'Form frmMyMainForm
Implements IMainForm

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

person RS Conley    schedule 23.09.2009
comment
+1. Параметры ActiveX exe - это пул потоков только с одним потоком, а класс имеет экземпляры MultiUse. Я думаю, это означает, что когда-либо запускается только один экземпляр. Я не передаю формы или элементы управления через границу процесса, это определенно ненадежно. - person MarkJ; 24.09.2009
comment
Вы можете использовать формы, если у вас есть форма, реализующая интерфейс, и в этом случае она обрабатывается как объект ActiveX. Я делал это годами. - person RS Conley; 24.09.2009