Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > ОС и железо
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 16.01.2017, 18:07
delphi-programmer-2007 delphi-programmer-2007 вне форума
Прохожий
 
Регистрация: 16.01.2017
Сообщения: 12
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию 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  
Старый 16.01.2017, 19:38
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

Была уже подобная тема. Как раз про IDispatch и String у WMI. Проверяй типы до того как делать преобразование.
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #3  
Старый 17.01.2017, 11:06
delphi-programmer-2007 delphi-programmer-2007 вне форума
Прохожий
 
Регистрация: 16.01.2017
Сообщения: 12
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от NumLock
Была уже подобная тема. Как раз про IDispatch и String у WMI. Проверяй типы до того как делать преобразование.

Так и так проверил, что тип-то varDispatch (в том числе в тех 99% случаях, когда все нормально работает). В 99% случаев он нормально преобразуется в String (причем использую в данном случае не свой код, а готовый из Интернета - и он на 99% компьютеров работает). А на 1% компьютеров возникает ошибка.

Даже непонятно, куда копать.

Что вообще с этим Dispatch делать.
Ответить с цитированием
  #4  
Старый 17.01.2017, 11:10
delphi-programmer-2007 delphi-programmer-2007 вне форума
Прохожий
 
Регистрация: 16.01.2017
Сообщения: 12
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от NumLock
Была уже подобная тема. Как раз про IDispatch и String у WMI. Проверяй типы до того как делать преобразование.

Честно, весь Интернет (весь Гугл и Яндекс) перерыл - да, есть что-то там про Dispatch и String - но применительно к данному случаю, совершенно не помогло.

И самое главное, непонятно, куда копать.

Что делать с этим Dispatch? Если не в string преобразовать - то во что еще можно преобразовать? Может, у Dispatch есть какие-то свойства или методы к которым можно обращаться (например, как с COM-объектом)?

И если у Dispatch есть методы - как узнать, какие у него есть методы?
Ответить с цитированием
  #5  
Старый 17.01.2017, 13:31
delphi-programmer-2007 delphi-programmer-2007 вне форума
Прохожий
 
Регистрация: 16.01.2017
Сообщения: 12
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Модуль 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  
Старый 17.01.2017, 20:30
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,015
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

IDispatch - это один из базовых интерфейсов, как TObject для обычных классов. Т.е. что за реальный объект "прячется" за этим интерфейсом заранее неизвестно.
Можно попробовать простой workaround. В случае, если у тебя не получается получить значение, ты все равно возвращаешь 'NULL'. Ну так перехвати исключение в верни этот 'NULL'. Типа:
Код:
try
  s3 := GetWMIstring('.', 'root\CIMV2', 'Win32_BaseBoard','SerialNumber')
except
  s3 := 'NULL'
end;
Ответить с цитированием
  #7  
Старый 18.01.2017, 11:54
delphi-programmer-2007 delphi-programmer-2007 вне форума
Прохожий
 
Регистрация: 16.01.2017
Сообщения: 12
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от lmikle
IDispatch - это один из базовых интерфейсов, как TObject для обычных классов. Т.е. что за реальный объект "прячется" за этим интерфейсом заранее неизвестно.
Можно попробовать простой workaround. В случае, если у тебя не получается получить значение, ты все равно возвращаешь 'NULL'. Ну так перехвати исключение в верни этот 'NULL'. Типа:
Код:
try
  s3 := GetWMIstring('.', 'root\CIMV2', 'Win32_BaseBoard','SerialNumber')
except
  s3 := 'NULL'
end;


Вообще говоря, временно так и пришлось сделать - от безысходности.

Правда, сделал немного не так, а вот так:

Код:
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.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра
Комбинированный вид Комбинированный вид

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 02:58.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter