Спасибо RRUZ за ответ - я узнал что-то новое - но, к сожалению, правильный ответ был «Не делай этого» (как это типично!).
Оказалось, что при перечислении Windows Boot Loader
объектовневозможно определить, какой из объектов является «текущим».Как я наконец узнал (благодаря статье Hey, Scripting Guy! из выпуска TechNet Magazine за июль 2008 года), правильный способ - открыть объект загрузчика напрямую по его общеизвестному идентификатору.(Который, опять же, хорошо скрыт и малоизвестен. Единственная официальная документация, которую мне удалось найти по известным BCD GUID, это Данные конфигурации загрузки в Windows Vista документ.)
Пример кода ниже сначала открывает объект BCD WMI.Затем он открывает хранилище по умолчанию и показывает информацию для объекта начальной загрузки {current}
(доступ к которому осуществляется с помощью известного идентификатора).
Затем он открывает объект Windows Boot Manager
(с использованием его известного идентификатора).), читает его элемент DefaultObject
для определения GUID загрузочной записи по умолчанию, открывает этот объект по его GUID и отображает информацию.
ShowLoaderInfo
отображает только ID
(GUID), Description
и NumberOfProcessors
(это была информация, которую я хотел получить из BCD).Забавный трюк заключается в том, что последний имеет тип BcdIntegerElement
, который возвращает свое значение через свойство Integer с «признаком», что возвращаемое значение не является целым числом, а строкой.В примечании от MSDN поясняется:
Целочисленное значение элемента.Значение передается в виде строки, потому что Automation изначально не поддерживает 64-битные целые числа.
(Да, отлично! Почему в любом случае оно должно быть 64-битным? Недостаточно 2 миллиардов процессоров?)
Полный список поддерживаемых Windows Boot Loader
элементов см. BcdOSLoaderElementTypes .
program ShowBCDInfo;
{$APPTYPE CONSOLE}
uses
SysUtils,
ComObj,
ActiveX;
const
Description = $12000004; //http://msdn.microsoft.com/en-us/aa362652(v=VS.85)
UseBootProcessorOnly = $26000060; //http://msdn.microsoft.com/en-us/aa362641(v=VS.85)
NumberOfProcessors = $25000061;
ForceMaximumProcessors = $26000062;
ProcessorConfigurationFlags = $25000063;
DefaultObject = $23000003; //http://msdn.microsoft.com/en-us/aa362641(v=VS.85)
CurrentGUID = '{fa926493-6f1c-4193-a414-58f0b2456d1e}'; //http://msdn.microsoft.com/en-us/windows/hardware/gg463059.aspx
WBMGUID = '{9dea862c-5cdd-4e70-acc1-f32b344d4795}';
function GetObject(const objectName: String): IDispatch;
var
bindCtx: IBindCtx;
moniker: IMoniker;
chEaten: Integer;
begin
OleCheck(CreateBindCtx(0, bindCtx));
OleCheck(MkParseDisplayName(bindCtx, StringToOleStr(objectName), chEaten, moniker));
OleCheck(moniker.BindToObject(bindCtx, nil, IDispatch, Result));
end;
procedure ShowLoaderInfo(const name: string; const obj: OleVariant);
var
objElement: OleVariant;
begin
Writeln(Format('%s ID: %s', [name, string(obj.id)]));
if obj.GetElement(Description, objElement) then
Writeln(Format('Description: %s', [objElement.String]));
if obj.GetElement(NumberOfProcessors, objElement) then
Writeln(Format('NumProc: %s', [objElement.Integer]));
end;
procedure ShowBcdInfo;
var
objBcdStore : OleVariant;
objWBL : OleVariant;
objWBM : OleVariant;
objWMIService: OleVariant;
begin
objWMIService := GetObject('winmgmts:{(Backup,Restore)}\\.\root\wmi:BcdStore');
if not objWMIService.OpenStore('', objBcdStore) then
Writeln('*** error opening store')
else begin
if objBcdStore.OpenObject(CurrentGUID, objWBL) then
ShowLoaderInfo('{current}', objWBL);
if objBcdStore.OpenObject(WBMGuid, objWBM) and
objWBM.GetElement(DefaultObject, objWBL) and
objBcdStore.OpenObject(string(objWBL.ID), objWBL)
then
ShowLoaderInfo('{default}', objWBL);
end;
end;
begin
try
OleInitialize(nil);
try
ShowBCDInfo;
finally OleUninitialize; end;
Readln;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
.