var Enum: IEnumVariant; Item: Variant; Value: LongWord; begin ... while Enum.Next(1, Item, Value) = 0 do begin end;Я думаю, что это до боли знакомый код многим. Я думаю, что почти все пробовали WMI. И не менее знакомы стенания по нему программистов, копирующих его один-к-одному, не удосужившись заглянуть в документацию и подумать головой.
Спокойно, в этой задачке нет никаких багов в Delphi или ещё каких подводных камней. Это простая задачка на умение читать MSDN и объяснять поведение.
Итак: какие-же стенания несчастных копипастеров мы можем услышать по этому коду, что в нём не так и как это исправить?
Ответ на задачку будет выложен как обычно: примерно через месяц.
Ответ.
тут все нормально, только Reset надо вначале сделать, если нужно перебрать элементы с самого начала
ОтветитьУдалитьЯ не дельфист, поэтому мне сложно сказать, не является ли ошибкой указывать вторым параметром простую переменную, тогда как MSDN говорит о массиве. Даже при том, что один элемент и запрашивается. Вероятно, в прототипе дельфисткого интерфейса там указан открытый массив, и компилятор автоматически приводит типы. Но поскольку явно сказано, что проблема не в Дельфи, видимо тут всё нормально.
ОтветитьУдалитьДругое дело, что третий параметр, являясь опциональным и при этом указателем, может быть опущен путём указания NULL. Ну в смысле Nil. А значит в прототипе должен стоять указатель. Здесь же передаётся простая переменная. Не думаю, что компилятор под капотом незаметно позволяет сводить объекты к указателям на них, так что раз скомпилилось, значит реализация, упрощая жизнь дельфистам, принимает третий параметр по ссылке, что делает невозможным его опциональность.
Ну ещё меня коробит от сравнения с 0. Мне пришлось покопаться в Win SDK, чтобы вспомнить, что S_OK действительно равен нулю.
Ну во-первых - это использование Item: Variant; вместо Item: OleVariant; что как бы чревато. Я даже не уверен скомпилируется ли это. Ну и я бы еще в конце цикла я бы поставил:
ОтветитьУдалитьwhile Enum.Next(1, Item, Value) = 0 do
begin
//тут что то делаем
VariantClear(Item);
end;
p.s. ну и есстественно должна быть проверка assigned(Enum) и VariantClear(Item); если Item до этого использовался в функции.