Question

If I have [in,out] BSTR* parameter and I want to modify the string content but still maintain the same length, can I just reuse it or do I need to realloc/free-and-alloc the BSTR?

MSDN says:

For [in, out] parameters, the caller allocates memory, the method or property can optionally deallocate and reallocate it, and the caller is finally responsible for deleting the memory.

To be more complete, when is it optional?

Was it helpful?

Solution

when is it optional

It says that caller is responsible to provide a valid argument (and allocate memory, if necessary).

The method (the callee) is responsible to leave the parameter with valid value as well. That is, at its discretion, it might choose to leave the existing value in place, or, optionally, change the value to another - when the method needs for any reason to alter the parameter. Changing allocatable value means that old allocation should be cancelled (deallocated) and new allocation is made the same way, so that caller receiving this value would safely deallocate when it no longer needs the value.

An in/out string parameter would look like this. On the first execution it increments input value's first character without re-allocations, then it will replace the value with a new one:

STDMETHOD(Method)(/* [in, out] */ BSTR* psValue) throw()
{
    if(!psValue)
        return E_POINTER;
    static INT g_nCounter = 0;
    if(++g_nCounter > 1)
    {
        // Deallocate old, Allocate new
        SysFreeString(*psValue);
        *psValue = SysAllocString(L"New Value");
    } else
    {
        // No Re-allocation
        if(SysStringLen(*psValue) > 0)
            (*psValue)[0]++;
    }
    return S_OK;
}

ATL based code might look a bit nicer:

STDMETHOD(Method)(BSTR* psValue) throw()
{
    _ATLTRY
    {
        ATLENSURE_THROW(psValue, E_POINTER);
        CComBSTR& sValue = reinterpret_cast<CComBSTR&>(*psValue);
        static INT g_nCounter = 0;
        if(++g_nCounter > 1)
        {
            sValue = _T("New Value");
        } else
        {
            if(sValue.Length() > 1)
                sValue[0]++;
        }
    }
    _ATLCATCH(Exception)
    {
        return Exception;
    }
    return S_OK;
}

A caller side code could be like this:

CComBSTR sValue = _T("Old Value");
Method(&sValue);
CComBSTR sValueA = sValue; // Gets you "Pld Value"
Method(&sValue);
CComBSTR sValueB = sValue; // Gets you "New Value"
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top