[技巧]C++ Builder 中慎用 Supports 函数来取接口的实例

实际上,这个问题在于 C++ Builder 是通过一个模板来处理接口的自动释放的,实际上相当于玩了一个auto_ptr,但 Supports 需要的第三个参数,确是一个指针,那么这个就用来比较麻烦了。

这样用:

_di_IQService AService;
if(Supports(PluginsManager()->ByPath(L"Services/Dock/Forms",__uuidof(IQFormService),AService))

编译能过去,但是得到的结果是不对的。

这样用:

_di_IQService AService;
if(Supports(PluginsManager()->ByPath(L"Services/Dock/Forms",__uuidof(IQFormService) ,&AService))

得到的 AService 是一个有效的值,但是,如果你重复调用时,由于 auto_ptr 的特性没有起作用,结果就会乱套了。而在重复下次调用前,你需要手动的调用接口的 release 去释放计数,显示太麻烦了,一个不注意应容易出错。

那么在 C++ Builder 中,难道我们就注意忧郁终生吗?不是的,新版的 C++ Builder 提供了一个 interface_cast 模板,可以让我们得到不差于 Delphi 中 Supports 的待遇,上面的代码实际上可以写成:

_di_IQServices AServices;
if((AService=interface_cast<IQServices>(PluginsManager()->ByPath(L"Services/Dock/Forms"))))
...

并不比 Delphi 的 Supports 差到那里去,是不是?而作为我们 QDAC 的用户,当然要提供进一步的待遇,在 QString 新为大家提供了一个更简单的 C++ 封装 HasInterface 和 ToInterface 定义,前者比 Delphi 的 Supports 可以少写一个参数,后者和 interface_cast 少写几个字母(主要是解决早期版本没带 interface_cast 的问题,但又懒的查从那个版本开始有的 interface_cast :-: ):

template<class T>
bool __fastcall HasInterface(IUnknown *AIntf, DelphiInterface<T> &AResult)
{
	T *ATemp;
	if (AIntf->QueryInterface(__uuidof(T), (void **)&ATemp) == S_OK)
	{
		AResult = ATemp;
		ATemp->Release();
		return true;
	}
	return false;
}

template<class T>
bool __fastcall HasInterface(TObject *AObject, DelphiInterface<T> &AResult)
{
	T *ATemp = NULL;
	if (AObject->GetInterface(__uuidof(T), &ATemp))
	{
		AResult = ATemp;
		ATemp->Release();
		return true;
	}
	return false;
}

template<class T>
DelphiInterface<T> __fastcall ToInterface(TObject *AObject)
{
DelphiInterface<T> ARetVal;
HasInterface(AObject, ARetVal);
return ARetVal;
}
template<class T>
DelphiInterface<T> __fastcall ToInterface(IUnknown *AIntf)
{
DelphiInterface<T> ARetVal;
HasInterface(AIntf, ARetVal);
return ARetVal;
}

而使用时,代码就变成了:

_di_IQService AService;
if(HasInterface(PluginsManager()->ByPath(L"Services/Dock/Forms",AService))
  {
   AService....
   }

是不是看起来更简洁了:)

分享到: