我有一个图像检测模块,它封装为COM模块。我已导出Key/Value Getter
API,例如:GetImageAttr(UINT key, void* pValue);
。我们的产品可能或可能不会在图像上附加特殊结构,因此我的客户可以通过此API查询特定结构。
可能的用法如下:
ImageSpecialAttribute attr = {};
HRESULT hr = pImageDetector->GetImageAttr(IMAGE_SPECIAL_ATTRIBUTE, (void*)&attr);
如果图像具有这样的附加结构,则返回S_OK
是微不足道的。但如果它没有,我应该返回E_FAIL还是S_FALSE?
S_FALSE:一切都很好,只是图片没有这样的可选属性。
E_FAIL:不!出了点问题。您不应该查询此密钥。
更新,(感谢Remy Lebeau)
HRESULT_FROM_WIN32(ERROR_NOT_FOUND):不!没有这样的元素/属性。
hr
来了解其含义。答案 0 :(得分:4)
S_FALSE
是成功值,而不是错误值。当方法本身成功但请求的数据不可用或未执行请求的操作时,Microsoft的许多COM API将返回S_FALSE
。这在Microsoft的文档中提到:
所有带有前缀“E_”的常量都是错误代码。常数S_OK和S_FALSE都是成功代码。可能99%的COM方法在成功时返回S_OK;但不要让这个事实误导你。方法可能会返回其他成功代码,因此请始终使用SUCCEEDED或FAILED宏来测试错误。
...
成功代码S_FALSE值得一提。有些方法使用S_FALSE来粗略地表示不是失败的负面情况。它也可以表示“无操作” - 方法成功,但没有效果。例如,如果您从同一个线程第二次调用它,CoInitializeEx函数将返回S_FALSE。如果您需要在代码中区分S_OK和S_FALSE,则应直接测试该值,但仍然使用FAILED或SUCCEEDED来处理剩余的情况......
我建议您遵循相同的惯例,例如:
HRESULT hr = pImageDetector->GetImageAttr(IMAGE_SPECIAL_ATTRIBUTE, (void*)&attr);
if (SUCCEEDED(hr))
{
if (hr != S_FALSE)
{
// use attribute as needed...
}
else
{
// attribute not found...
}
}
else
{
// error...
}
如果您确实要为不存在的属性返回错误代码,建议您为该特定条件定义自定义HRESULT
,例如:
#define E_ATTR_NOT_FOUND MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 1)
或者:
#define E_ATTR_NOT_FOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND)
然后您可以将该错误返回给调用者,例如:
HRESULT hr = pImageDetector->GetImageAttr(IMAGE_SPECIAL_ATTRIBUTE, (void*)&attr);
if (SUCCEEDED(hr))
{
// use attribute as needed...
}
else if (hr == E_ATTR_NOT_FOUND)
{
// attribute not found...
}
else
{
// error...
}
COM没有为“未找到”条件定义标准化错误HRESULT代码(HRESULT_FROM_WIN32(ERROR_NOT_FOUND)
将是最接近的标准等值)。
答案 1 :(得分:1)
我建议关注the pattern of COM enumerators' Next
method
其中检索的对象数在输出参数中返回。 (如果对象计数为零但调用无效,则还会返回S_FALSE
)
因为它是一个输出参数,所以客户端不能忽略它,而VB等隐藏用户HRESULT的图层不会导致丢失信息。