|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
|||
|
|||
Could not convert variant of type Dispatch into type(String) - ошибка
Имеется программа с привязкой к материнской плате и процессору, все нормально в целом работает.
Привязка выполняется на основе функции GetWMIString (код на Delphi 7 приведен ниже), В целом все нормально работает на 99% компьютерах. Но есть одна проблема, которая проявляется на 1% компьютеров и совсем непонятно, что с этим делать. Выскакивает ошибка could not convert variant of type Dispatch into type(String) - причем выскакивает она в строке, которая в коде функции помечена соответствующим комментарием. Что было проверено: Пытался копать - проверил следующее: ShowMessage(inttostr(VarType(colItem.Properties_.I tem(wmiProperty, 0)))) - выдет 9 - то есть тип проблемного выражения, которое не присваивается переменной result, varDispatch Там точно не NULL. Вместо VarIsNull(colItem.Properties_.Item(wmiProperty, 0)) пробовал еще VarIsClear(colItem.Properties_.Item(wmiProperty, 0)) - то же самое - попадает на 2-ю ветку. Дальше куда копать - непонятно Что интересно, функция GetWMIstring иногда работает (даже на этих проблемных 1% компьютерах) - например, s1 := GetWMIstring('.', 'root\CIMV2', 'Win32_BaseBoard','Product') //работает s2 := GetWMIstring('.', 'root\CIMV2', 'Win32_BaseBoard','Manufacturer') //работает s3 := GetWMIstring('.', 'root\CIMV2', 'Win32_BaseBoard','SerialNumber') //НЕ РАБОТАЕТ В чем может быть причина? Код функции: Код:
function GetWMIstring0(wmiHost, root, wmiClass, wmiProperty: string): string; var objWMIService: OLEVariant; colItems: OLEVariant; colItem: OLEVariant; oEnum: IEnumvariant; iValue: LongWord; function GetWMIObject(const objectName: String): IDispatch; var chEaten: Integer; BindCtx: IBindCtx; Moniker: IMoniker; begin OleCheck(CreateBindCtx(0, bindCtx)); OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten, Moniker)); //здесь ошибка OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result)); end; begin objWMIService := GetWMIObject(Format('winmgmts:\\%s\%s',[wmiHost,root])); colItems := objWMIService.ExecQuery(Format('SELECT * FROM %s',[wmiClass]),'WQL',0); oEnum := IUnknown(colItems._NewEnum) as IEnumVariant; while oEnum.Next(1, colItem, iValue) = 0 do begin if VarIsNull(colItem.Properties_.Item(wmiProperty, 0)) then Result := 'NULL' else begin //при выполнении следующей команды будет ошибка "could not convert variant of type Dispatch into type(String)" Result := colItem.Properties_.Item(wmiProperty, 0) end end; end; |
#2
|
||||
|
||||
Была уже подобная тема. Как раз про IDispatch и String у WMI. Проверяй типы до того как делать преобразование.
Пишу программы за еду. __________________ |
#3
|
|||
|
|||
Цитата:
Так и так проверил, что тип-то varDispatch (в том числе в тех 99% случаях, когда все нормально работает). В 99% случаев он нормально преобразуется в String (причем использую в данном случае не свой код, а готовый из Интернета - и он на 99% компьютеров работает). А на 1% компьютеров возникает ошибка. Даже непонятно, куда копать. Что вообще с этим Dispatch делать. |
#4
|
|||
|
|||
Цитата:
Честно, весь Интернет (весь Гугл и Яндекс) перерыл - да, есть что-то там про Dispatch и String - но применительно к данному случаю, совершенно не помогло. И самое главное, непонятно, куда копать. Что делать с этим Dispatch? Если не в string преобразовать - то во что еще можно преобразовать? Может, у Dispatch есть какие-то свойства или методы к которым можно обращаться (например, как с COM-объектом)? И если у Dispatch есть методы - как узнать, какие у него есть методы? |
#5
|
|||
|
|||
Модуль System смотрел - нашел там
Код:
varDispatch = $0009; { vt_dispatch 9 } IDispatch = interface(IUnknown) ['{00020400-0000-0000-C000-000000000046}'] function GetTypeInfoCount(out Count: Integer): HResult; stdcall; function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall; function GetIDsOfNames(const IID: TGUID; Names: Pointer; NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall; function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall; end; Пробовал обращаться к colItem.Properties_.Item(wmiProperty, 0) через какой-нибудь метод Dispatch - например, пробовал Код:
var Count: integer colItem.Properties_.Item(wmiProperty, 0).GetTypeInfoCount(Count) - думал, это поможет определить количество методов или свойств, доступных для обращения к Dispatch - не помогло (ошибку выдает и все) - похоже, этих методов что в System описаны нет у Dispatch |
#6
|
|||
|
|||
IDispatch - это один из базовых интерфейсов, как TObject для обычных классов. Т.е. что за реальный объект "прячется" за этим интерфейсом заранее неизвестно.
Можно попробовать простой workaround. В случае, если у тебя не получается получить значение, ты все равно возвращаешь 'NULL'. Ну так перехвати исключение в верни этот 'NULL'. Типа: Код:
try s3 := GetWMIstring('.', 'root\CIMV2', 'Win32_BaseBoard','SerialNumber') except s3 := 'NULL' end; |
#7
|
|||
|
|||
Цитата:
Вообще говоря, временно так и пришлось сделать - от безысходности. Правда, сделал немного не так, а вот так: Код:
try s3 := GetWMIstring('.', 'root\CIMV2', 'Win32_BaseBoard','SerialNumber') except on E:Exception do s3 := E.Message end; чтобы было более более информативно, чем в случае с 'NULL'. Но это плохое решение. Вполне может получиться, что на некоторых компьютерах все четыре GetWMIString будут выдавать значение NULL и таким образом, теряется вообще смысл привязки программы к материнской плате и процессору. Кроме того, пользователь может поменять операционную систему (например, поменять Windows 7 на Windows 10) и может так получиться, что GetWMISTring будет уже другим для другой операционной системы ... Хотелось бы все-таки по-нормальному решить проблему или хотя бы понять причину ошибки. И понять, как вытащить этот SerialNumber, либо узнать, что он действительно NULL и его вытащить невозможно. Ведь Dispatch-то какой-то есть и он явно не пустой. И явно что-то с ним можно сделать. Только понять нужно, что с ним делать и что можно сделать. Понять, куда копать. А так получается, только гадать можно (методом тыка, например) - какие методы могут быть у этого Dispatch - никак не узнать? Последний раз редактировалось delphi-programmer-2007, 18.01.2017 в 12:00. |