ActiveX控件属性的动态访问(128分)

龙丹

Unregistered / Unconfirmed
GUEST, unregistred user!
Delphi 的 Inport ActiveX Control...引入ActiveX控件时,为我创建了_TLB文件,文件中
列出了控件的属性,但我的问题是,我要使用那些属性是不确定的,在运行期间,根据配置
或用户选择的属性名称来确定。
我如何在运行期间根据属性名称(字符串)来访问属性?
或者
我如何获取ActiveX控件的属性列表?
 
看来这分得退给我了!
 
说说你的答案也不妨吧?分数可以给你的。
 
Delphi在_TLB文件中生成了一个基于TOleControl的控件(类),该控件发布了OCX的所有可
发布属性,而另一方面,通过RTTI可以访问Delphi标准控件的发布属性,我现在就是这样间
接地访问OCX的属性。
但是,我是希望能够直接访问OCX的属性(可以不要那个_TLB文件)。
 
如果你的OCX是一个可视控件,你怎么能不通过
delphi import xxx_tlb.pas而在程序中使用呢?
 
to 温柔一刀:
OCX也未必就是可视的啊。

这个问题的实质是需要了解OCX的内部结构。只是我的实际应用只要得到属性表并根据属性名
获取属性值即可。

因为我已有替代的解决办法,若近日仍无人回答,请坛主适时结束吧(无满意答案,我不知如何发分)。
 
To 龙丹:
你好,近日我也為不同ActiveForm之間傳替參數而發愁,我的需求是:在多個ActiveForm
之間傳全局變量,懇請幫忙解決(最好給代碼,加100分!)
 
To liyu:
抱歉了,我帮不了你。到目前为止,我还没有做过ActiveForm一类的东西。
 
如果是普通的参数很容易传递,在activexform里new一个属性,通过他传递参数.
 
>>OCX也未必就是可视的啊。

我没说“OCX一定就是可视的”啊,我说的是“如果”,目的是想澄清你提出的问题
是不是和我理解的一样,事实证明是 -- “只是我的实际应用只要得到属性表并根据属性名获取属性值即可”。
因此看来我的理解能力没问题,但是表达能力还是... :-( -- 想要言简意赅就那么难吗?

这个问题我有一些兴趣,不要着急结束,等我出差回来再看两眼。
(其实早就有这种想法了,没别人提出的话,总觉得可能没意义)
 
总算找到一个同志了!
 
所有的OleControl(ActiveX Control)的属性和方法都是通过IDispatch接口访问的,

1、调用TOleControl的QueryInterface(IID_IDispatch, Obj)获得Dispatch接口的指针;

2、若1成功则调用获得的Dispatch接口的GetIDsOfNames函数,通过名字得到DISPID(Dispatch接口中的相关属性
或方法的ID)

3、若2成功则根据得到的DISPID调用Dispatch接口的Invoke函数,来获得属性值或调用其方法
(在Ole中,获得属性和调用方法的方式相同,都是通过Invoke,但是注意标志,如
DISPATCH_METHOD,DISPATCH_PROPERTYGET,DISPATCH_PROPERTYPUT等等)

我用VC作过,Delphi还没试过,应该没问题。例子在VC中满地都是,Delphi中也应该有。
试试吧!
 
控件的属性列表则通过控件的TypeInfo接口可以得到,得到Dispatch接口指针后,调用
GetTypeInfoCount,往往返回1,或2,第一个接口就是属性和方法的描述,第2个ITypeInfo
接口可能是事件描述的接口,然后调用GetTypeInfo?(可能是吧)得到ITypeInfo接口,
调用ITypeInfo的函数,然后获得函数的数量,根据每一个函数的描述来判断是属性(还分get和put)
还是方法,然后取得该属性的名称,DISPID(Dispatch ID,或称MemberID)

哎呀呀,给你一段C++的代码你自己看吧

BOOL CPropertyWnd::AddDispatch(IUnknown* pIUnknown)
{
IDispatch *pDispatch;
pIUnknown->QueryInterface(IID_IDispatch, (void **)&pDispatch);
ITypeInfo *pTypeInfo;

if (pDispatch == NULL)
return FALSE;

pDispatch->GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, &pTypeInfo);

if (pTypeInfo == NULL)
return FALSE;

TYPEATTR* pta;
pTypeInfo->GetTypeAttr(&pta);

if (pta->typekind == TKIND_INTERFACE)
{
// 取得第二个接口
ITypeInfo *pInfoTemp;
HREFTYPE hRef;
HRESULT hr = pTypeInfo->GetRefTypeOfImplType(-1, &hRef);
if (FAILED(hr))
return FALSE;

hr = pTypeInfo->GetRefTypeInfo(hRef, &pInfoTemp);
if (FAILED(hr))
return FALSE;

pTypeInfo->ReleaseTypeAttr(pta);
pTypeInfo = pInfoTemp;
pTypeInfo->GetTypeAttr(&pta);
}

int nItem = m_ListCtrl.GetItemCount();

for (int i = 0
i < pta->cFuncs
i++)
{
FUNCDESC* pfd;
pTypeInfo->GetFuncDesc(i, &amp;pfd);
if (pfd->invkind &amp
DISPATCH_PROPERTYGET
&amp;&amp
(pfd->wFuncFlags &amp
(FUNCFLAG_FRESTRICTED | FUNCFLAG_FHIDDEN)) == 0)
{
switch (pfd->elemdescFunc.tdesc.vt)
{
case VT_USERDEFINED:
case VT_EMPTY:
case VT_NULL:
case VT_I2:
case VT_I4:
case VT_R4:
case VT_R8:
case VT_CY:
case VT_DATE:
case VT_BSTR:
case VT_ERROR:
case VT_BOOL:
case VT_VARIANT:
case VT_DECIMAL:
case VT_I1:
case VT_UI1:
case VT_UI2:
case VT_UI4:
case VT_INT:
case VT_UINT:
case VT_PTR:
{
ITypeInfo* pUserTypeInfo = NULL;
VARTYPE vt;
vt = pfd->elemdescFunc.tdesc.vt;

if (pfd->elemdescFunc.tdesc.vt == VT_USERDEFINED)
{
HREFTYPE hrt = pfd->elemdescFunc.tdesc.hreftype;
vt = VT_USERDEFINED;
HRESULT hr = E_FAIL;
hr = GetEnumTypeInfo(pTypeInfo, hrt, &amp;pUserTypeInfo);
if(FAILED(hr))
vt = GetUserDefinedType(pTypeInfo, hrt);
}

/* if (pfd->elemdescFunc.tdesc.vt == VT_PTR)
{
HREFTYPE hrt = pfd->elemdescFunc.tdesc.lptdesc->hreftype;
VARTYPE vt = pfd->elemdescFunc.tdesc.lptdesc->vt;

if (SUCCEEDED(pTypeInfo->GetRefTypeInfo(hrt, &amp;pUserTypeInfo)))
{
ITypeLib *pITypeLib;
UINT nIndex = NULL;
if (SUCCEEDED(pUserTypeInfo.p->GetContainingTypeLib(&amp;pITypeLib, &amp;nIndex)))
{
CComBSTR bStr = NULL;
pITypeLib.p->GetDocumentation(nIndex, &amp;bStr, NULL, NULL, NULL);

if (bStr == "IFontDisp")
bStr = "Font";
else if (bStr == "IPictureDisp")
bStr = "Picture";
else
continue;

CComVariant varVal;
CComBSTR bstrVal;
CComBSTR bstrDocString;

CComDispatchDriver dd(pDisp);
dd.GetProperty(pfd->memid, &amp;varVal);
CProperty* pProp = new CProperty(pDisp, pfd->memid, varVal, vt, bstrDocString, spUserTypeInfo);
pProp->GetStringValue(&amp;bstrVal);

m_list.AddItem(nItem, 0, OLE2T(bStr));
m_list.AddItem(nItem, 1, OLE2T(bstrVal));
m_list.SetItemData(nItem, reinterpret_cast<DWORD>(pProp));
nItem++;
}
}
continue;
}
*/
COleVariant varVal;
BSTR bstrVal;
BSTR bstrName;
BSTR bstrDocString;

pTypeInfo->GetDocumentation(pfd->memid, &amp;bstrName, &amp;bstrDocString, NULL, NULL);

DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
pDispatch->Invoke(pfd->memid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
&amp;dispparamsNoArgs, &amp;varVal, NULL, NULL);

CProperty* pProp = new CProperty(pDispatch, pfd->memid, varVal, bstrDocString, pUserTypeInfo);
pProp->GetStringValue((BSTR*)&amp;bstrVal);

CString strName = bstrName;
CString strVal = bstrVal;

AddItem(nItem, 0, strName);
AddItem(nItem, 1, strVal);

m_ListCtrl.SetItemData(nItem, reinterpret_cast<DWORD>(pProp));
nItem++;
}
}
}
pTypeInfo->ReleaseFuncDesc(pfd);
}
pTypeInfo->ReleaseTypeAttr(pta);
return S_OK;
}


试试吧!
 
to George
关于IDispatch接口能否说得详细些!
 
IDispatch接口是每一个ActiveX Control必须的接口(如果它有属性和方法的话)
M$在设计Automation时的可能希望所有的属性和方法都通过一种方式来调用,以解决
不同控件所拥有的不同的属性和方法,同时又定义了一大堆描述常量、函数、参数的
结构来这些东西(现在想想头还有点晕).

IDispatch

QueryInterface Returns pointers to supported interfaces.
AddRef Increments the reference count.
Release Decrements the reference count.

GetTypeInfoCount Retrieves the number of type information interfaces.
GetTypeInfo Retrieves the type information for an object.
GetIDsOfNames Maps a single member and an optional set of argument names to a corresponding set of integer DISPIDs.
Invoke Provides access to properties and methods exposed by an object.
 
多人接受答案了。
 
http://www.sina.com.cn
 
dfwsfsdfd
sdfsdfsdfsdfdssdsdfsdfds​
 
werwerewrwerewrwer we rwe rwe rwerwwerwerwerwerwerwerwerewrew
 
我的实验http://www.sina.com别打我
 
顶部