IDL 中的示例方法:
HRESULT _stdcall a_method( [in] long value, [out] BSTR *comment );
我的函数逻辑是,对于某些值,不需要注释。如果客户端使用 comment == NULL
调用此函数,我是否应该抛出异常?或者可以宽容并允许这种情况发生吗?
(我正在用 C++ 开发我的对象)。
我尝试严格参数检查的理由是我担心内存泄漏,以及让客户端根据 COM 规范进行正确的调用,但我的对象不接受调用。
最佳答案
[out]
参数的语义对此非常明确。
获取[out]
参数的方法永远不应该查看参数的值,直到它在其中添加内容。这是未初始化的内存。垃圾。事实上,如果您的方法是通过编码调用(公寓间或进程间)调用的,则垃圾正是您得到的:您的调用者在调用您的方法时可能放置的任何内容,都会被代理丢弃并忽略 stub ;你永远不会得到它。
如果客户端/调用者在调用你的方法之前在参数上放置了一些东西,那么这绝对是内存泄漏(当然,假设它是像 BSTR 这样的已分配对象),但这是调用者的错误。被调用的方法从来没有责任来处理它。被调用的方法即使想要处理泄漏也无法处理。
如果您想处理调用者可能传入的任何值,则需要使用 [in, out]
参数而不是 [out]
。
最后一个警告:自动化客户端(VBA、VBScript 等)不支持[out]
参数。自动化将默默地处理任何 [out]
参数,就好像它是 [in, out]
一样,这会让您处于尴尬的境地:客户端在参数中放置的任何值应用程序将会被泄露,而你的方法对此无能为力。
如果您计划由自动化客户端使用您的对象,请不要使用 [out]
参数。请改用 [in, out]
,并确保在调用之前检查调用者是否在参数上设置了值。代理/ stub 将始终以两种方式编码 [in, out]
参数的值。如果调用者在调用之前在参数上放置了一个值,则您的方法负责在写入参数之前释放该值。
编辑:扩展指针本身为 NULL:
您可以考虑检查 NULL 并在为 NULL 时返回 E_INVALIDARG
,但我不建议这样做。
将 NULL 作为[out]
参数的指针值传递是非法的。即使您的代码处理 NULL 值,如果对调用进行编码,编码器也会遇到访问冲突。编码器必须在返回时访问指向的值(以将编码输出存储在其上),并且它将在不检查 null 的情况下执行此操作。
在您的特定场景中(调用语义是在给定情况下没有任何内容可返回),正确的过程是调用者始终提供指向存储的指针,并让被调用方法将值设置为 NULL 。像这样的事情:
// Caller
BSTR comment;
hr = obj->a_method( 42, &comment);
// Callee
HRESULT a_method( value, BSTR *comment )
{
if (...)
{
//... I've decided we don't need to return a comment
*comment = NULL;
}
...
}
如果您确实想要拥有您提到的纯空指针语义,您可以;但您必须使用 [ptr]
属性来标记参数。据我所知,这对于自动化客户端来说效果不佳,并且您必须使用自定义编码器。如果您不打算使用自动化客户端,这显然是一个选择。
关于com - 我应该强制输出参数为非 NULL 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24520852/