3

我正在尝试将此代码片段转换为 Delphi,但我被困在for each objWBL in colObjects.

if not objBcdStore.EnumerateObjects( &h10200003, colObjects ) then
    WScript.Echo "ERROR objBcdStore.EnumerateObjects( &h10200003 ) failed."
    WScript.Quit(1)
end if

for each objWBL in colObjects
    WScript.Echo ""
    WScript.Echo "Windows Boot Loader"
    WScript.Echo "-------------------"

    WScript.Echo "identifier              " & GetBcdId( objWBL.Id )

    If objWBL.Id = current then

      if not objWBL.GetElement(BcdOSLoaderInteger_NumberOfProcessors, objElement ) then
          WScript.Echo "ERROR WBL GetElement for " & Hex(BcdOSLoaderInteger_NumberOfProcessors) & " failed."
          WScript.Quit(1)
      end if
      WScript.Echo "numproc              " & objElement.Integer

      if not objWBL.GetElement(BcdOSLoaderBoolean_UseBootProcessorOnly, objElement ) then
          WScript.Echo "ERROR WBL GetElement for " & Hex(BcdOSLoaderBoolean_UseBootProcessorOnly) & " failed."
          WScript.Quit(1)
      end if
      WScript.Echo "onecpu              " & objElement.Boolean

    end if
next

我的部分 q&d 翻译(注意,必须是管理员才能运行它):

uses
  OleAuto,
  ActiveX;

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 TForm44.btnClick(Sender: TObject);
var
  colObjects   : OleVariant;
  objBcdStore  : OleVariant;
  objWMIService: OleVariant;
begin
  objWMIService := GetObject('winmgmts:{impersonationlevel=Impersonate,(Backup,Restore)}!root/wmi:BcdStore');
  if not objWMIService.OpenStore('', objBcdStore) then
    Caption := 'error'
  else begin
    objBcdStore.EnumerateObjects($10200003, colObjects);
    //???
  end;
end;

EnumerateObjects定义为

boolean EnumerateObjects(
  [in]   uint32 Type,
  [out]  BcdObject Objects[]
);

我不知道如何在 Delphi 中遍历 BcdObject 数组。

4

2 回答 2

8

您必须使用VarArrayLowBoundandVarArrayHighBound函数来获取函数返回的变量数组的边界,EnumerateObjects然后您可以使用for循环来迭代数组的元素。

检查这个样本

Uses
 ComObj,
 ActiveX;

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 TForm44.Button1Click(Sender: TObject);
var
  colObjects   : OleVariant;
  objBcdStore  : OleVariant;
  objWMIService: OleVariant;

  i : Integer;
  objWBL : OleVariant;
begin
  objWMIService := GetObject('winmgmts:{impersonationlevel=Impersonate,(Backup,Restore)}!root/wmi:BcdStore');
  if not objWMIService.OpenStore('', objBcdStore) then
    Caption := 'error'
  else
  begin
    objBcdStore.EnumerateObjects($10200003, colObjects);
       if not VarIsNull(colObjects) and VarIsArray(colObjects) then
       for i := VarArrayLowBound(colObjects, 1) to VarArrayHighBound(colObjects, 1) do
       begin
          objWBL:=colObjects[i];
          //do your stuff here


       end;
  end;
end;
于 2011-09-22T16:28:52.820 回答
1

感谢 RRUZ 的回答——我学到了一些新东西——但遗憾的是,正确的答案是“不要那样做”(多么典型!)。

事实证明,通过枚举Windows Boot Loader对象,无法找出哪些对象是“当前”对象。我终于发现(感谢TechNet 杂志 2008 年 7 月号中的“嘿,脚本专家! ”一文),正确的方法是直接通过它的知名 ID 打开加载器对象。(这又是隐蔽且不为人所知的。我设法在著名的 BCD GUID 上找到的唯一官方文档是Windows Vista文档中的引导配置数据。)

下面的示例代码首先打开 BCD WMI 对象。然后它打开默认存储并显示{current}引导条目对象的信息(通过众所周知的 ID 访问)。

接下来,它打开Windows Boot Manager对象(通过使用其众所周知的 ID),读取其DefaultObject元素以确定默认引导条目的 GUID,通过其 GUID 打开该对象并显示信息。

ShowLoaderInfo仅显示ID(GUID)DescriptionNumberOfProcessors(这是我想从 BCD 获得的信息)。这里一个有趣的技巧是后者是BcdIntegerElement类型,它通过 Integer 属性返回其值,具有一个“特征”,即返回的值不是整数而是字符串。MSDN的注释解释说:

元素的整数值。该值作为字符串传递,因为自动化本身不支持 64 位整数。

(是的,太好了!为什么它必须是 64 位的?20 亿个处理器还不够吗?)

有关受支持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.
于 2011-09-23T09:52:26.383 回答