Почему перечисления TypeLib не отображаются как перечисления в Visual Basic 6.0? - PullRequest
6 голосов
/ 22 сентября 2010

У меня есть проект VB6, который ссылается на COMSVCSLib, и один из методов делает вызовы SharedPropertyGroupManager.CreateProperGroup группы COMSVCSLib, передавая LockMethod и Process в качестве параметров.

Убран код VB6:

Dim groupName       As String
Dim spmMgr          As COMSVCSLib.SharedPropertyGroupManager
Dim spmGroup        As COMSVCSLib.SharedPropertyGroup

Dim bGroupExists    As Boolean

Set spmMgr = New COMSVCSLib.SharedPropertyGroupManager

With spmMgr
    Set spmGroup = .CreatePropertyGroup(groupName, LockMethod, Process, bGroupExists)

End With

Не работая с VB6 уже несколько лет, сначала я подумал, что LockMethod и Process являются переменными или константами, определенными где-то еще внутри проекта.

После небольшого исследования Object Browser я обнаружил, что они оба были представлены как константы в COMSVCSLib.

Object Browser

Но, глядя на их определение в OLE / COM Object Viewer, кажется, что они определены как значения перечисления:

typedef enum {
    LockSetGet = 0,
    LockMethod = 1
} __MIDL___MIDL_itf_autosvcs_0469_0002;

Почему перечисления IDL / TypeLib из COMSVCSLib не отображаются как перечисления в Visual Basic 6.0?

Ответы [ 2 ]

11 голосов
/ 22 сентября 2010

Отказ от ответственности : Я не эксперт по IDL (Язык определения интерфейса, который используется для определения типов COM) или компилятору Microsoft IDL (MIDL), но я пришел квыводы ниже, после игры с библиотекой типов для scrrun.dll, которая имеет аналогичную проблему с enum.Часть этой информации была получена из краткого обзора этой статьи DevX по IDL и VB6: IDL для VB Tutorial

VB6 ожидает, что фактическое перечисление будет иметь имя, а не простоперечисление, которое typedef соответствует имени.Имя __MIDL___MIDL_itf_autosvcs_0469_0002 является заполнителем, так как исходная библиотека типов не определила имя перечисления в том же typedef, где определены константы перечисления.

Когда вы просматриваете библиотеку типов в OLE Viewer,enum, вероятно, выглядит так:

typedef [public] __MIDL___MIDL_itf_autosvcs_0469_0002 LockModes;

typedef enum {
    LockSetGet = 0,
    LockMethod = 1
} __MIDL___MIDL_itf_autosvcs_0469_0002;

Первый typedef создает публичное имя LockModes в качестве псевдонима для автоматически сгенерированного MIDL___MIDL_itf_autosvcs_0469_0002 имени, которое было присвоено enum.Когда исходная библиотека типов была скомпилирована, компилятор midl сгенерировал длинное имя __MIDL для исходного enum и автоматически создал псевдоним typedef, указывающий на него.

Исходный IDL, вероятно, определил перечисление следующим образом:

typedef enum {
     LockSetGet = 0,
     LockMethod = 1
} LockModes;

Когда компилятор midl обрабатывает определение enum, написанное таким образом, он автоматически генерирует имя для enum (поскольку он отсутствует - он должен появляться после ключевого слова enum).Это имя __MIDL, которое вы видите при просмотре библиотеки типов в OLE Viewer.Компилятор midl также автоматически генерирует вторую typedef, которая связывает имя typedef с автоматически сгенерированным именем enum.

Проблема состоит в том, что VB6 не может понять перечисления, созданные этимпуть.Он ожидает, что все будет в одном typedef (то есть вы даете enum имя, а также присваиваете имя typedef):

typedef enum LocksMode {
    LockSetGet = 0,
    LockMethod = 1
} LocksMode;

IDL обрабатывает typedef то же самоеКак это делает C или C ++: вам не нужно присваивать самому enum имя, потому что typedef уже имеет имя, но вы можете дать enum имя, если вы выберете.Другими словами, typedef и enum на самом деле являются двумя отдельными сущностями.VB6 случайно распознает typedef и enum как две разные, но неопределенно связанные вещи, поэтому в вашем случае он видит typedef с именем __MIDL___MIDL_itf_autosvcs_0469_0002 и видит, что это псевдоним неназванногоenum, и он также видит typedef для LockModes, который является общедоступным псевдонимом для другого typedef.

Поскольку первый typedef является общедоступным, вы увидите запись для LockModes в обозревателе объектов, и поскольку это псевдоним для перечисления, вы также увидите константы перечисления в обозревателе объектов.Тем не менее, само фактическое перечисление не имеет имени (поэтому он получает фанки автоматически сгенерированного имени, назначенного ему в браузере), и VB6 не может использовать перечисление, потому что автоматически сгенерированное имя происходитбыть недопустимым в VB6 (имена с двойным подчеркиванием автоматически скрываются в VB6).

Чтобы продемонстрировать эту последнюю точку, если вы введете это в коде VB6, Intellisense будет работать и компилироваться, но, очевидно,он не очень идеален:

MsgBox COMSVCSLib.[__MIDL___MIDL_itf_autosvcs_0469_0002].LockMethod

Причина, по которой этот код работает, заключается в том, что вы можете помещать имена, которые обычно вызывают синтаксические ошибки (например, имена, начинающиеся с подчеркиваний), в скобках, чтобы VB6 мог принимать обычно незаконныеназвание.Кроме того, префикс констант с автоматически сгенерированным именем работает с Intellisense, потому что это фактическое имя, которое VB6 связывает с enum (помните, что typedef - это просто псевдоним этого «реального», но автоматическисгенерированное имя, и VB6, по-видимому, не может собрать все части вместе, чтобы понять, что оба имени относятся к одному и тому же enum).

Вместо того, чтобы вводить смехотворно длинное имя, как указано выше, вы также можете получить доступ к enum констант, добавив к ним префикс имени библиотеки, например, COMSVCSLib.LockMethod, должно работать.Мне менее понятно, почему это действительно работает, и я не уверен, что произойдет, если два разных enum определяют константы с одинаковым именем.

Наконец, вы можете решить эту проблему по-другому, используя IDL из OLE Viewer для создания пользовательского файла IDL, в котором вы заменяете существующие enum typedefs на typedef для каждого enum, который просто дает как enum, так и typedef одно и то же имя (т.е. typedef enum LockModes { ... } LockModes;), но поскольку OLE Viewer не обязательно генерирует действительный IDL, вам, вероятно, придется настроить его еще больше, чтобы он действительно компилировался , Если вы можете заставить это работать, то вы можете ссылаться на ваш пользовательский .tlb из вашего проекта VB6 (вместо библиотеки COMSVCSLib), и enum будут работать так, как вы ожидаете.

Если вы хотите пойти по этому пути, вам нужны еще два инструмента, которые уже должны быть установлены на вашем компьютере разработчика (но вам, возможно, придется их искать):

  • midl.exe: Этот инструмент может генерировать файл typelib (* .tlb) из файла .idl. Таким образом, вы можете скопировать IDL из OLE Viewer в Блокнот, изменить определения enum, как описано выше, сохранить его как файл .idl и передать его в midl.exe для создания новой библиотеки типов:

    midl my-custom-typelib.idl

  • regtlib.exe: Этот инструмент может зарегистрировать файл .tlb, который необходим, если вы хотите добавить его в качестве ссылки на ваш проект VB6:

    regtlib.exe my-custom-typelib.tlb

Однако создание пользовательской библиотеки типов для этого, вероятно, излишне, и, как уже упоминалось, может быть трудно получить скомпилированный файл IDL, основанный на выводе из OLE Viewer, поскольку он отображает IDL с обратной инженерией для библиотеки типов , а не оригинальный IDL.

1 голос
/ 22 сентября 2010

Выставляется как перечисление. Выберите LockModes в списке классов и посмотрите на нижний информационный раздел. Вы увидите, что это перечисление. Или вы можете ввести LockModes. в своем коде, и вы получите два варианта.

В средстве просмотра объектов каждый элемент в перечислении идентифицируется как постоянное значение, но не является отдельным константой. При выборе элемента <globals> в списке классов отдельные константы отображаются отдельно.

...