是否可以通过OleVariant类型获取COM对象的成员列表(属性,函数,过程)?
例如,
var
wscript: Olevariant;
begin
wscript := CreateOleObject("WScript.Shell");
...
end;
我对获取WScript.Echo,WScript.Quit等功能列表特别感兴趣。
我想拥有此功能,因为它可以实现代码自动完成。
答案 0 :(得分:7)
您可以使用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.
答案 1 :(得分:2)
对象可以实现IDispatchEx
,然后您可以使用GetNextDispID
枚举所有成员,GetMemberName
和GetMemberProperties
来发现有关每个成员的一些(最小)信息。
或者,对象可以实现IDispatch
,特别是IDispatch::GetTypeInfo
,然后您可以(有些困难)从ITypeInfo
对象中提取有关其成员的信息。
在你提问之前,我不知道如何在Delphi中做任何这些。
如果其他所有方法都失败了,您可以read the documentation。