Почему функция VBA VarType сообщает, что этот COM-объект является строкой?(Объект является экземпляром COM-версии .NET-класса System.Object.) Это ошибка? - PullRequest
5 голосов
/ 12 апреля 2019

Сводка вопроса

Когда я использую функцию VBA VarType, передавая ей экземпляр класса Object, доступный в справочнике библиотеки mscorlib.dll ( .NET ссылка на библиотеку), возвращаемое значение равно 8.

Согласно документации VBA здесь , это означает, что объект является строкой. Это кажется смешным.

У меня вопрос: почему функция VarType возвращает значение строкового типа для экземпляров этого класса Object из ссылки VBA библиотеки .NET? Это ошибка?

Справочная информация

Я подозреваю, что тот факт, что функция VBA VarType говорит о том, что определенный COM-объект является строкой, может быть причиной того, что у меня возникают проблемы с использованием функции DispCallFunc в некоторых методах определенных COM объекты. COM-объекты - это COM-версии объектов .NET, доступные через .NET Framework.

Я использую ссылку VBA mscorlib.dll, чтобы получить функциональность раннего связывания для этих объектов. Ссылка относится к версии 4.0.30319 .NET Framework. На моем компьютере библиотека типов для справки хранится по адресу:

C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ mscorlib.tlb

.

Похоже, когда метод объекта указывает, что аргумент или возвращаемое значение имеют тип System.Object, DispCallFunc не работает для меня. В любом случае, это отдельная проблема, которая косвенно связана с проблемой, которой посвящен этот вопрос.


На момент написания статьи я использую последнюю версию Excel (версия 1903, сборка 11425.20202). Моя операционная система Windows 8.1.

Когда я использую функцию VarType с экземплярами других классов из библиотеки mscorlib.dll, я иногда получаю возвращаемые значения 9 & 13 (VbVarType.vbObject & VbVarType.vbDataObject константы), что кажется правильным.

Я проверил в Интернете, чтобы выяснить, не сталкивался ли кто-то еще с этой проблемой, но ничего не смог найти.

Код, который можно использовать для воспроизведения проблемы

Dim o As mscorlib.Object
Set o = New mscorlib.Object
Debug.Print "TypeName(o) = " & TypeName(o) ' TypeName function seems to work correctly.
Debug.Print "o.Equals(o) = " & o.Equals(o) ' System.Object.Equals method is working.

Debug.Print "VarType(CVar(o)) = " & VarType(CVar(o)) ' IMPORTANT LINE
' VBA VarType function says o is string (type 8) but it isn't?!

Debug.Print "VbVarType.vbString = " & VbVarType.vbString

Я ожидал, что VarType(CVar(o)) вернет 9, 13 или другое подходящее целое число. Вместо этого он возвратил 8, что кажется не совсем подходящим (8 представляет строки.)

Ответы [ 3 ]

8 голосов
/ 13 апреля 2019

Если вы откроете typeLib C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb с помощью OleView , например, и перейдете к интерфейсу _Object (не первый _Object, dispinterface, но второй), вы увидите это :

enter image description here

Итак, метод .NET Object.ToString() объявлен клиентам COM / Automation как

[id(00000000), propget, custom(54FC8F55-38DE-4703-9C4E-250351302B1C, 1)]
HRESULT ToString([out, retval] BSTR* pRetVal);

Это означает, что он виден COM-клиентам, которые понимают этот "синтаксический сахар" (VB / VBA / VBScript / JScript / .NET и т. Д.) Как свойство (propget + out + retval) с именем ToString, который возвращает String (BSTR).

Теперь id(0) означает, что это свойство по умолчанию , потому что 0 представляет DISPID_VALUE , специальный известный идентификатор.

И, наконец, VB / VBA Документация VarType гласит:

Если объект имеет свойство по умолчанию, VarType (объект) возвращает тип свойства объекта по умолчанию.

(что я всегда находил довольно странным дизайнерским решением ...)

1 голос
/ 13 апреля 2019

Глядя на справочный источник для object.cs, я не вижу никаких атрибутов [DispId], но если предположить, что первый член будет маршалирован с [DispId(0)], то это сделает метод ToString тип COM * член по умолчанию .

Это единственное объяснение, которое я имею для Debug.Print o, выводящего System.Object, вместо того, чтобы взрываться с ошибкой 438, как это обычно происходит без элемента по умолчанию.

Таким образом, проблема не столько в взаимодействии .NET / COM, сколько в том, чтобы иметь дело с получением метаданных из объекта, который имеет элемент по умолчанию: у вас будет точно такая же проблема с любым объектом COM, который имеет String член по умолчанию:

?VarType(Application), VarType(Application.Name)
 8             8 

Я не могу придумать, как сделать так, чтобы VarType работал с ними. С другой стороны, проверка TypeOf...Is работает нормально:

?TypeOf Application Is Object
True

Таким образом:

Debug.Print TypeOf o Is Object ' True
0 голосов
/ 12 апреля 2019

Я думаю, что отчасти проблема в том, что VBA оценивает выражения в определенных случаях (возможно, кто-то может добавить больше информации о том, когда и почему это происходит).Поэтому, когда вы делаете вызов VarType(o), переменная o фактически преобразуется в строковое представление, и берется тип.

Например, если вы пишете Debug.Print o,вывод будет System.Object.Если вы напишите Debug.Print x на другом конкретном объекте, система, возможно, выдаст ошибку.

Попробуйте следующий синтаксис:

Debug.Print VarType(o.GetType)

В моем случае это возвращает значение 13.

...