Cannot read BCDStore info on Windows 2012 Server using WMI
Asked Answered
F

1

15

We are using the following function to get the number of processors specified by the current boot configuration. This number is used purely for logging.

The function below works fine on XP, Vista, 7, 2003 and 2008. It, however, fails on the Windows 2012 Server.

// -1 = not implemented or not allowed
//  0 = not limited
// >0 = number of processors in the {current} boot entry
function Internal_GetBCDNumberOfProcessors: integer;
var
  objBcdStore  : OleVariant;
  objElement   : OleVariant;
  objWBL       : OleVariant;
  objWMIService: OleVariant;
begin
  // for more info, see: https://mcmap.net/q/826550/-accessing-bcdstore-from-delphi/7527164#7527164
  Result := -1;
  try
    objWMIService := GetObject('winmgmts:{(Backup,Restore)}\\.\root\wmi:BcdStore');
    if (not VarIsNull(objWMIService)) and
       boolean(objWMIService.OpenStore('', objBcdStore)) and
       (not VarIsNull(objBcdStore)) and
       boolean(objBcdStore.OpenObject('{fa926493-6f1c-4193-a414-58f0b2456d1e}', objWBL)) and
       (not VarIsNull(objWBL))
    then
      if objWBL.GetElement($25000061, objElement) and //<-- fails here on Server 2012
         (not VarIsNull(objElement))
      then
        Result := StrToIntDef(objElement.Integer, 0)
      else
        Result := 0;
  except
    on E: EOleSysError do
      Result := -1;
  end;
end;

If I try to run it on Win2012, the objWBL.GetElement raises EOleSysError exception with text OLE error D0000225. Google doesn't find anything meaningful related to this error code :(

Stack trace says that the exception is triggered in System.Win.ComObj.DispatchInvokeError which is called by the DispatchInvoke which is called by the VarDispInvoke.

All this was reproduced using XE2. I could try to repeat the problem with XE3 but I don't believe Delphi RTL has anything to do with it.

Does anybody has any idea about possible reasons for this behaviour?

Foresheet answered 4/1, 2013 at 14:29 Comment(11)
Do you have Update 4 hotfix 1?Iqbal
Yes, I should have. I'll double-check. (Exe was built on the build server which should have U4H1 installed.)Foresheet
UAC on or off? Process elevated or not elevated?Carlstrom
UAC on, tested as a service and as an elevated GUI process. No difference.Foresheet
You can try using VbScript to get the error description , try this sample pastebin.com/ALmnk4R0Adenoma
@DavidHeffernan, also doesn't work with XE3. The RTL is not the problem here (I think). The reason must lie in some Microsoft modifications to the BCD.Foresheet
@Adenoma Somehow I'm not able to run that even on Windows XP - I get "Error to execute GetElement"Foresheet
I mentioned that because I got hit qc.embarcadero.com/wc/qcmain.aspx?d=109377 recently. This bug was introduced in XE2 UP4 and then fixed in UP4 hotfix 1. Then, later, the same bug was re-released in XE3 RTM due to QA fail at Emba. And then fixed in XE3 UP1. You mentioned DispatchInvokeError which sounded familiar to me. Anyway, I expect you are right that this is an issue outside the Delphi compiler.Iqbal
@gabr, are you sure which the line of code objWBL.GetElement($25000061, objElement) and (not VarIsNull(objElement)) returns true in your XP system or in another windows version?Adenoma
@Adenoma GetElement returns True on my machines. If no custom BCD boot is active, objElement returned is Null.Foresheet
@Foresheet The D0000225 error code seems to be related to the Windows update components according to these URL : answers.microsoft.com/en-us/windows/forum/windows_10-update/… and answers.microsoft.com/en-us/windows/forum/…Fireside
F
2

The GetElement part:

if objWBL.GetElement($25000061, objElement) and //<-- fails here on Server 2012
   (not VarIsNull(objElement))
then
  Result := StrToIntDef(objElement.Integer, 0)
else
  Result := 0;

can be replace with EnumerateElements:

if objWBL.EnumerateElements(objArray) then try
  for i := VarArrayLowBound(objArray, 1) to VarArrayHighBound(objArray, 1) do begin
    objElement := objArray[i];
    if objElement.Type = $25000061 then
      Exit(objElement.Integer);
  end;
finally VarClear(objArray); end;

This doesn't raise the EOleException, but sadly also doesn't find the NumberOfProcessors element.

Foresheet answered 4/4, 2016 at 12:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.