Jump to content
Phil Brinkle

How do I enumerate all properties of a Variant?

Recommended Posts

Greetings!

 

I am working with an undocumented third-party COM server via WMI interface.

var
  ACPIObj : ISWbemObject;
  DataPackProp : ISWbemProperty;
  OutParam: ISWbemObject;
  PropValue : Variant;
begin
//...
OutParam:=ACPIObj.ExecMethod_('GetObjectData', nil, 0, nil);
if OutParam <> nil then begin
  DataPackProp:=OutParam.Properties_.Item('DataPack’,0);
  PropValue:=DataPackProp.Get_Value;
//..
end;

After executing a method called ‘GetObjectData’, PropValue is actually storing an IDispatch interface, since it has the VarType of varDispatch. Is there a way of enumerating all the properties stored in the PropValue variable?

 

Thank you!

Share this post


Link to post

Yes, you can.

Basically, you have to call GetTypeInfoCount(), GetTypeInfo(), GetTypeAttr() and other functions (All documented by Microsoft).

Here is a function to list all method names including property getter/setter. Similar code can enumerate argument list, argument data types and return value data type.

 

procedure DisplayMethodNames(
    const DispIntf : IDispatch;
    const IntfName : String;
    Strings        : TStrings);
var
    Count            : Integer;
    TypeInfo         : ITypeInfo;
    TypeAttr         : PTypeAttr;
    FuncDesc         : PFuncDesc;
    HR               : HRESULT;
    I                : Integer;
    FuncName         : WideString;
begin
    if IntfName <> '' then
        Strings.Add(IntfName);

    Count := 0;
    HR := DispIntf.GetTypeInfoCount(Count);
    if Failed(HR) or (Count = 0) then
        Exit;

    HR := DispIntf.GetTypeInfo(0, 0, TypeInfo);
    if Succeeded(HR) and (TypeInfo <> nil) then begin
        TypeAttr := nil;
        HR       := TypeInfo.GetTypeAttr(TypeAttr);
        if Succeeded(HR) and (TypeAttr <> nil) then begin
            for I := 0 to TypeAttr.cFuncs - 1 do begin
                FuncDesc := nil;
                HR       := TypeInfo.GetFuncDesc(I, FuncDesc);
                if Succeeded(HR) and (FuncDesc <> nil) then begin
                    TypeInfo.GetDocumentation(FuncDesc.memid,
                                              @FuncName,
                                              nil,  // DocString,
                                              nil,  // HelpContext
                                              nil); // HelpFile
                    if Length(FuncName) <> 0 then
                        Strings.Add(Format('  %-3d %s', [I, FuncName]));
                    TypeInfo.ReleaseFuncDesc(FuncDesc);
                end;
            end;
            TypeInfo.ReleaseTypeAttr(TypeAttr);
        end;
    end;
end;

 

Edited by FPiette
  • Like 6

Share this post


Link to post

Thank you for your quick reply, sir!

 

Your code works fine and it returns 36 functions for me:

  0   QueryInterface
  1   AddRef
  2   Release
  3   GetTypeInfoCount
  4   GetTypeInfo
  5   GetIDsOfNames
  6   Invoke
  7   Put_
  8   PutAsync_
  9   Delete_
  10  DeleteAsync_
  11  Instances_
  12  InstancesAsync_
  13  Subclasses_
  14  SubclassesAsync_
  15  Associators_
  16  AssociatorsAsync_
  17  References_
  18  ReferencesAsync_
  19  ExecMethod_
  20  ExecMethodAsync_
  21  Clone_
  22  GetObjectText_
  23  SpawnDerivedClass_
  24  SpawnInstance_
  25  CompareTo_
  26  Qualifiers_
  27  Properties_
  28  Methods_
  29  Derivation_
  30  Path_
  31  Security_
  32  Refresh_
  33  SystemProperties_
  34  GetText_
  35  SetFromText_

Now I have to examine it to know how to retrieve all the properties of an IDispatch interface, since I am not familiar with COM programming. Thank you for you help!

 

Share this post


Link to post

Thanks. If you like my answer, please mark it as such (The heart icon on the right side of my answer).

Maybe you have a type library ? If you import it into Delphi, you'll have all the information.

 

Edited by FPiette

Share this post


Link to post
Guest
4 hours ago, FPiette said:

Thanks. If you like my answer, please mark it as such (The heart icon on the right side of my answer).

Mr. Piette! I now have a go-to-guy re COM/OLE 🙂

Seriously, don't worry, i avoid OLE like i do Covid.

Ahem, not true, i'm more afraid of OLE than Covid.

'll give you one anyways!

Hmm.. still above you 🙂 la-di-da... (not for long though, deep into deliveries for at least ½ a year on)...

Share this post


Link to post
On 10/28/2020 at 7:15 PM, FPiette said:

Thanks. If you like my answer, please mark it as such (The heart icon on the right side of my answer).

Maybe you have a type library ? If you import it into Delphi, you'll have all the information.

 

I am sorry, I don't have one, since I am working with an undocumented COM server.

 

BTW, experimentally I found out that the PropValue variable has one property of Result which is an array of bytes. So, using TempArrayBuffer:=PropValue.Result I can read the content of the array. Do you know the way of enumerating all the properties of the PropValue variant? I believe there should be other properties. Thank you!

Edited by Phil Brinkle

Share this post


Link to post
On 10/28/2020 at 10:02 PM, Dany Marmur said:

Seriously, don't worry, i avoid OLE like i do Covid.

Maybe if you learned the difference between OLE and COM you wouldn't be so scared... Hardly anyone uses OLE anymore.

Share this post


Link to post
44 minutes ago, Phil Brinkle said:

I am working with an undocumented COM server.

Undocumented doesn't mean it has not documentation inside the exe/dll. The proof is that my function show the list of functions. Try to import the DLL in Delphi as it is a type library (Delphi Menu Component / Import component / Import a Type Library. If it doesn't appear in the list, click the Add button and select your  dll. If it doesn't work, try adding it as an ActiveX instead.

Share this post


Link to post
On 10/28/2020 at 4:45 PM, Phil Brinkle said:

Your code works fine and it returns 36 functions for me

Those are just the WMI methods and they are all documented.

https://docs.microsoft.com/en-us/windows/win32/api/wbemcli/nn-wbemcli-iwbemclassobject

 

If you want to talk to a COM server why are you then going through WMI? Are you sure it isn't a WMI Provider you are talking about?

 

52 minutes ago, Phil Brinkle said:

I am working with an undocumented COM server.

If you install the Windows SDK (just the tools parts) there's a utility in it called OleView that you can use to examine type libraries and COM servers.

 

The type library of your server is probably embedded in the EXE file.

 

Edit: If it's a WMI provider then it's probably a DLL and it's probably early bound and without a type library. It depends on what kind of provider it is.

Edited by Anders Melander
  • Like 1

Share this post


Link to post

Instead of waiting on the back and forth I'll assume that what we have here is a classic case of the XY problem.

 

To determine what properties a WMI object exposes you can use a tool like WMI Explorer (there are many other tools like that, this is just the first one I found).

Share this post


Link to post

It's a BIOS ACPI object which can be accessed through WMI (root/wmi namespace) only. WMI Explorer is a very good software since it lets me execute methods of objects. I have been using it for months, thanks! But it cannot pass an array of values to a WMI method, only an integer.

 

Anyway, I much appreciate your assistance, guys!

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×