I have a image detection module which is encapsulated as a COM module. I've exported a Key/Value Getter API like: GetImageAttr(UINT key, void* pValue);. Our product MAY or MAY NOT attach a special structure on image, so my client can query the specific structure through this API.
Possible usage is like:
ImageSpecialAttribute attr = {};
HRESULT hr = pImageDetector->GetImageAttr(IMAGE_SPECIAL_ATTRIBUTE, (void*)&attr);
It is trivial to return S_OK if the image does have such attached structure. But if it doesn't, should I return E_FAIL or S_FALSE?
S_FALSE: Everything is fine, just the image does not have such optional attribute.
E_FAIL: No! Something is wrong. You should not query this key.
Updated, (Thanks to Remy Lebeau)
HRESULT_FROM_WIN32(ERROR_NOT_FOUND): No! No such element/attribute existed.
hr.S_FALSE is a success value, not an error value.  Many of Microsoft's own COM APIs return S_FALSE when the method itself succeeds but the requested data is not available, or the requested operation is not performed. This is mentioned in Microsoft's documentation:
Error Handling in COM
All of the constants with the prefix "E_" are error codes. The constants S_OK and S_FALSE are both success codes. Probably 99% of COM methods return S_OK when they succeed; but do not let this fact mislead you. A method might return other success codes, so always test for errors by using the SUCCEEDED or FAILED macro.
...
The success code S_FALSE deserves mention. Some methods use S_FALSE to mean, roughly, a negative condition that is not a failure. It can also indicate a "no-op"—the method succeeded, but had no effect. For example, the CoInitializeEx function returns S_FALSE if you call it a second time from the same thread. If you need to differentiate between S_OK and S_FALSE in your code, you should test the value directly, but still use FAILED or SUCCEEDED to handle the remaining cases...
I suggest you follow the same convention, eg:
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...
}
If you really want to return an error code for a non-existing attribute, I suggest you define a custom HRESULT for that specific condition, eg:
#define E_ATTR_NOT_FOUND MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 1)
Or:
#define E_ATTR_NOT_FOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND)
And then you can return that error to the caller, eg:
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 does not define a standardized error HRESULT code for a "not found" condition (HRESULT_FROM_WIN32(ERROR_NOT_FOUND) would be the closest standard equivilent).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With