When using COM, I typically rely on ATL smart pointers, like ATL::CComPtr
and ATL::CComBSTR
, for resource management. But some of the methods I'm calling use output parameters to return pointers to allocated storage that I have to free. For example:
WCHAR *pszName = nullptr;
if (SUCCEEDED(pShellItem->GetDisplayName(SIGDN_FILESYSPATH, &pszName))) {
DoSomething(pszName);
CoTaskMemFree(pszName);
}
Note that GetDisplayName
allocates memory for the string and returns a pointer to it through the output parameter. It's the caller's responsibility to free that memory with CoTaskMemFree
.
If DoSomething
throws an exception, then the above code will leak. I'd like to use some sort of smart pointer for pszName
to avoid such leaks, but the API takes WCHAR**
, so I don't see how I can pass anything but the address of a dumb pointer. Since I'm not the one allocating, I can't use RAII.
I can use RRID if I can make a deleter like this:
struct CoTaskMemDeleter {
void operator()(void *p) { ::CoTaskMemFree(p); }
};
And then immediately assign the returned pointer to a standard smart pointer like this:
WCHAR *pszName = nullptr;
if (SUCCEEDED(pShellItem->GetDisplayName(SIGDN_FILESYSPATH, &pszName))) {
std::unique_ptr<WCHAR, CoTaskMemDeleter> guard(pszName);
DoSomething(pszName);
}
That works, but it seems error-prone to introduce an extra guard variable. For example, this approach leaves pszName
pointing at the released memory, so it would be easy to accidentally use it again.
Is there a cleaner way to use a smart pointer or an RAII wrapper for COM-server allocated memory returned by output parameter? Am I missing something that ATL provides?
ATL already has this one out of the box:
CComHeapPtr<WCHAR> pszName;
const HRESULT nResult = pShellItem->GetDisplayName(..., &pszName);
// Hooray, pszName will be CoTaskMemFree'd for you on scope leave
// via ~CComHeapPtr
CHeapPtr
can be derived to implement other resource releasers in a similar way. CComHeapPtr
is a MSDN documented class .
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