![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
|
|
#1
|
|||
|
|||
|
Имеется программа с привязкой к материнской плате и процессору, все нормально в целом работает.
Привязка выполняется на основе функции 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. |