是否可以通过 OleVariant 类型获取 COM 对象的成员列表(属性、函数、过程)?
例如,
var
wscript: Olevariant;
begin
wscript := CreateOleObject("WScript.Shell");
...
end;
我对获取 WScript.Echo、WScript.Quit 等函数列表特别感兴趣。
我想要这个功能,因为它很好地实现了代码自动完成。
您可以使用GetTypeInfo
方法和ITypeInfo
接口。
试试这个示例代码(不完整,但您可以将其用作起点)
{$APPTYPE CONSOLE}
uses
SysUtils,
ActiveX,
ComObj,
Variants;
//http://spec.winprog.org/typeinfo/
//http://spec.winprog.org/typeinf2/
//http://spec.winprog.org/typeinf3/
function GetTypeStr(tdesc : TTypeDesc; Context : ActiveX.ITypeinfo):string;
var
tinfo : ActiveX.ITypeInfo;
bstrName : WideString;
begin
case tdesc.vt of
VT_PTR : Result:=GetTypeStr(tdesc.ptdesc^,Context);
VT_ARRAY : Result:=Format('Array of %s',[GetTypeStr(tdesc.padesc^.tdescElem,Context)]);
VT_USERDEFINED : begin
context.GetRefTypeInfo(tdesc.hreftype, tinfo);
tinfo.GetDocumentation(-1, @bstrName, nil, nil, nil);
Result:=bstrName;
end
else
Result:=VarTypeAsText(tdesc.vt);
end;
end;
//http://msdn.microsoft.com/en-us/magazine/dd347981.aspx
Procedure InspectCOMOnbject(const ClassName: string);
Var
ComObject : OleVariant;
Dispatch : IDispatch;
Count : Integer;
i,j,k : Integer;
Typeinfo : ActiveX.ITypeinfo;
ptypeattr : ActiveX.PTypeAttr;
pfuncdesc : ActiveX.PFuncDesc;//http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.vswizard.tagfuncdesc.aspx
rgbstrNames : TBStrList;
cNames : Integer;
bstrName : WideString;
bstrDocString : WideString;
sValue : string;
sinvkind : string;
begin
ComObject := CreateOleObject(ClassName);
Dispatch := IUnknown(ComObject) as IDispatch;
OleCheck(Dispatch.GetTypeInfoCount(Count));
for i := 0 to Count-1 do
begin
OleCheck(Dispatch.GetTypeInfo(i,0,Typeinfo));
OleCheck(Typeinfo.GetTypeAttr(ptypeattr));
try
case ptypeattr^.typekind of
TKIND_INTERFACE,
TKIND_DISPATCH :
begin
for j:=0 to ptypeattr^.cFuncs-1 do
begin
OleCheck(Typeinfo.GetFuncDesc(j, pfuncdesc));
try
OleCheck(Typeinfo.GetNames(pfuncdesc.memid, @rgbstrNames, pfuncdesc.cParams + 1, cNames));
OleCheck(Typeinfo.GetDocumentation(pfuncdesc.memid,@bstrName,@bstrDocString,nil,nil));
if 1=1 then //pfuncdesc.elemdescFunc.tdesc.vt<>$0018 then
begin
//pfuncdesc.elemdescFunc.paramdesc
case pfuncdesc.invkind of
INVOKE_FUNC : if pfuncdesc.elemdescFunc.tdesc.vt = VT_VOID then sinvkind :='procedure' else sinvkind :='function';
INVOKE_PROPERTYGET : sinvkind :='get property';
INVOKE_PROPERTYPUT : sinvkind :='put property';
INVOKE_PROPERTYPUTREF : sinvkind :='ref property';
else
sinvkind :='unknow';
end;
{
if bstrDocString<>'' then
Writeln(Format('// %s',[bstrDocString]));
}
if pfuncdesc.cParams<=1 then
begin
if pfuncdesc.elemdescFunc.tdesc.vt = VT_VOID then
Writeln(Format('%s %s;',[sinvkind,bstrName]))
else
Writeln(Format('%s %s : %s;',[sinvkind,bstrName,GetTypeStr(pfuncdesc.elemdescFunc.tdesc, Typeinfo)]));
end
else
begin
sValue:='';
for k := 1 to pfuncdesc.cParams do
begin
//Writeln(Format('%s : %d',[rgbstrNames[k], pfuncdesc.lprgelemdescParam[k-1].tdesc.vt]));
sValue:= sValue + Format('%s : %s',[rgbstrNames[k], GetTypeStr(pfuncdesc.lprgelemdescParam[k-1].tdesc,Typeinfo)]);
if k<pfuncdesc.cParams then
sValue:=sValue+';';
end;
if pfuncdesc.elemdescFunc.tdesc.vt = VT_VOID then
Writeln(Format('%s %s (%s);',[sinvkind, bstrName, sValue]))
else
Writeln(Format('%s %s (%s) : %s;',[sinvkind, bstrName,SValue,GetTypeStr(pfuncdesc.elemdescFunc.tdesc, Typeinfo)]))
end;
//Writeln(pfuncdesc.elemdescFunc.tdesc.vt);
end;
finally
Typeinfo.ReleaseFuncDesc(pfuncdesc);
end;
end;
end;
end;
finally
Typeinfo.ReleaseTypeAttr(ptypeattr);
end;
end;
end;
begin
try
CoInitialize(nil);
try
//InspectCOMOnbject('WbemScripting.SWbemLocator');
InspectCOMOnbject('Excel.Application');
//InspectCOMOnbject('Schedule.Service');
//InspectCOMOnbject('WScript.Shell');
finally
CoUninitialize;
end;
except
on E:EOleException do
Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Press Enter to exit');
Readln;
end.
该对象可以实现IDispatchEx
,然后您可以使用它GetNextDispID
来枚举所有成员,并GetMemberName
发现GetMemberProperties
有关每个成员的一些(最少)信息。
或者,对象可以实现IDispatch
,特别是,然后您可以(有一些困难)从对象中IDispatch::GetTypeInfo
提取有关其成员的信息。ITypeInfo
在你问之前,我不知道如何在 Delphi 中做这些。
如果一切都失败了,您可以阅读文档。