从编组调用的角度来看规则(即当对象位于不同的 COM 单元时,或者当它位于不同的进程或机器中时会发生什么);您将了解规则是如何运作的,以及为什么它是唯一合理的规则。
关键事实是,对于[out]
参数,编组器不会将初始值编组给被调用者。
这意味着在进行调用之前您在变量中输入的内容并不重要。它可以是垃圾或NULL。没有人会看它。
注意:这也意味着如果变量在调用之前包含需要释放的东西,你必须在调用之前自己释放它,否则会泄漏。编组器不会为您释放它(因为作为参数[out]
,编组器必须假定它是垃圾)并且被调用者即使想要也无法释放它(因为它永远不会从编组器获得现有值)。
第二,调用返回后,被调用者无法知道你对返回值做了什么,所以唯一能释放参数的,就是调用者。
有错误条件的情况有点危险。
原则上,COM 要求[out]
在返回之前必须将参数设置为一致的(“marshallable”?)值(NULL 或等效值,或有效值),即使存在错误也是如此。这也是“唯一明智的规则”:编组器无法知道被调用者处于错误情况。它也不会根据 HRESULT 进行猜测,因为即使是“错误类”HRESULT 也不意味着该方法不打算将值返回给调用者。编组器会将参数的值编组回调用者 - 错误或无错误 - 所以参数最好是有效的,否则编组器本身会崩溃。
在实践中……嗯,有些对象比其他对象写得更好,有些 COM 类从不通过编组调用,因此类的开发人员永远不会发现问题。不符合这些规则的类不能在公寓间安全使用。
即使面对错误情况,确保参数值保持一致的规范方法如下所示:
STDMETHODIMP Class::Method(BSTR *pValue)
{
*pValue = NULL; // 1) Initialize all the [out] parameters before
// doing anything, to make sure they are always
// consistent
BSTR tempValue; // 2) Use a temporary to hold any result value
... // 3) Use the temporary for all computations
... // Finish all other processing
*pValue = tempValue; // 4) Only after all possible error conditions
// are behind us, do put the new value
// in the output parameter
return S_OK;
}
显然,如果 out 参数只是一个不需要释放的值(如 int 等),那么这些都不重要。