Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot read BCDStore info on Windows 2012 Server using WMI

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: http://stackoverflow.com/questions/7517965/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?

like image 427
gabr Avatar asked Jan 04 '13 14:01

gabr


1 Answers

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.

like image 50
gabr Avatar answered Oct 16 '22 00:10

gabr