在ASP开发中,我们经常会用到类似这样的调用 oUserName=Request("UserName")。可以肯定的是,我们需要得到的是一个字符串值,事实上,我们也把oUserName作为一个字符值来使用。
作为一个完整的调用应该是这样的:oUserName=CStr(Request.Item("UserName"))
接下来我们看,Request对象是如何通过COM自动化技术来支持形如Request("UserName")的调用的。
通过查看类型库,知道Request对象派生自接口IRequest,IRequest提供如下只读属性的申明。
[id(00000000), propget]
HRESULT Item(
[in] BSTR bstrVar,
[out, retval] IDispatch** ppObjReturn);
只读属性Item的DISPID为0,说明它是一个缺省属性,通过脚本调用时,不必显式写出。该属性的传入参数是一个字符串,传出值是一个IDispatch*接口指针。原来,上面得到的oUserName其实是一个IDispatch接口,并不是字符串值,只是在后面的调用中会自动实现IDispatch接口到字符串的转换,从而在表面上我们可以直接把它作为一个字符串来看待。
下面的问题是,IDispatch接口怎么就会自动转换。在自动化编程中,对于各种自动化类型之间的转换主要通过VariantChangeType和VariantChangeTypeEx进行。
下面是函数VariantChangeTypeEx的声明
HRESULT VariantChangeTypeEx(
VARIANTARG * pvargDest,
VARIANTARG * pvarSrc,
LCID lcid,
unsigned short wFlags,
VARTYPE vt
);
MSDN中对函数有这么一段解释。
An object is coerced to a value by invoking the object's Value property (DISPID_VALUE).
翻译过来是,通过调用对象的Value属性(属性ID为DISPID_VALUE),将此对象强制转换为一个值。
其中DISPID_VALUE就是0,VariantChangeType在进行转换时,如果发现pvarSrc是一个IDispatch接口,就会自动调用DISPID为0的属性方法,从而由这个属性方法来具体实现IDispatch接口到其他值的转换。
IDispatch接口具体转换成什么类型的值,由DISPID为0的属性方法决定。
下面我们写一个简单的实例:
定义一个对象CTest,实现接口ITest,ITest又派生自IDispatch;ITest定义一个属性Item
第一步:先生成接口ITest及对象CTest
interface ITest: IDispatch {
[id(00000000), propget]
HRESULT Item(
[out, retval] VARIANT* pVariantReturn);
};
class ATL_NO_VTABLE CTest :
public CComObjectRootEx
,
public CComCoClass,
public IDispatchImpl
{
public:
........................
public:
// ITest Methods
public:
STDMETHOD(get_Item)(VARIANT * pVariantReturn)
{
CComVariant pvResult=L"This is a test";
pvResult.Detach(pVariantReturn);
return S_OK;
}
第二步:
在其他要实现的对象中
STDMETHOD(get_Item)(BSTR bstrVar, LPDISPATCH * ppObjReturn)
{
CComObject
*pTest;
CComObject
::CreateInstance(&pTest);
return pTest->QueryInterface(IID_IDispatch,(void**)ppObjReturn);
}