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

VarArrayLowBoundand関数を使用して、VarArrayHighBound関数によって返されるバリアント配列の境界を取得する必要があります。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 Magazineの2008年7月号のHey、Scripting Guy!の記事に感謝します)、正しい方法は、既知のIDでローダーオブジェクトを直接開くことです。(これもまた、よく隠されていて、よく知られていません。よく知られているBCD GUIDで見つけた唯一の公式ドキュメントは、Windows Vistaドキュメントのブート構成データです。)

以下のサンプルコードは、最初にBCDWMIオブジェクトを開きます。次に、デフォルトストアを開き、{current}ブートエントリオブジェクト(既知のIDによってアクセスされる)の情報を表示します。

次に、Windows Boot Manager(既知のIDを使用して)オブジェクトを開き、そのDefaultObject要素を読み取ってデフォルトのブートエントリのGUIDを決定し、そのGUIDでこのオブジェクトを開き、情報を表示します。

ShowLoaderInfoID(GUID)、DescriptionおよびNumberOfProcessors(BCDから取得したい情報)のみを表示します。ここでの面白いトリックは、後者がBcdIntegerElementIntegerプロパティを介して値を返すタイプであり、戻り値が整数ではなく文字列であるという「機能」を備えていることです。MSDNからのメモは次のように説明しています。

要素の整数値。Automationは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 に答える