CString 的 ReleaseBuffer 会释放 Shell 分配的 CoTaskMemAlloc 字符串吗?

Will CString's ReleaseBuffer release Shell Allocated CoTaskMemAlloc String?

本文关键字:CoTaskMemAlloc 字符串 分配 Shell ReleaseBuffer 释放 CString      更新时间:2023-10-16

我相信,通过查看本文,我可以安全地使用CStrings来存储某些Windows API函数的返回字符串结果。

例如,我可以执行以下操作(不是我的代码,来自我上面链接的文章):

   //GetCurrentDirectory gets LPTSTR
   CString strCurDir;
   ::GetCurrentDirectory(MAX_PATH, strCurDir.GetBuffer(MAX_PATH));
   strCurDir.ReleaseBuffer();

GetCurrentDirectory 以"常规"方式分配数据。我知道我也可以使用 STL wstring 来做到这一点。

现在我的问题是,我可以安全地做到这一点吗?

int main()
{
    CString profileRootPath;
    HRESULT result = SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, (PWSTR*)&profileRootPath);
    wcout << profileRootPath.GetString();
    profileRootPath.ReleaseBuffer();
    Sleep(10000);
    return 0;
}

根据SHGetKnownFolderPath的MSDN页面,SHGetKnownFolderPath输出的数据需要通过调用CoTaskMemFree来取消分配。因此,对 ReleaseBuffer 的调用是否无效?还是会正常工作?在这种情况下,使用任何字符串类并仅使用普通的 C 样式数组来保存数据,然后在数组上使用 CoTaskMemFree 不是个好主意吗?如果代码无效,最正确的方法是什么?

使用 ATL,代码片段可能像这样简单:

CComHeapPtr<WCHAR> pszPath;
HRESULT result = SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, (PWSTR*) &pszPath);
CString sPath(pszPath);
wcout << sPath.GetString();

~CComHeapPtr将执行超出范围CoTaskMemFree,并且构造函数CString将值视为const WCHAR*

没有CComHeapPtr你可以这样做:

WCHAR* pszPath = nullptr;
HRESULT result = SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, (PWSTR*) &pszPath);
CString sPath(pszPath);
CoTaskMemFree(pszPath);
wcout << sPath.GetString();

GetCurrentDirectory只是将内存指针用于存储字符串,因此使用堆栈变量是有意义的,因为它的初始化和清理成本为零。如果你需要一个字符串,你可以从堆栈字符数组构建它 - 这消除了调用ReleaseBuffer的必要性:

TCHAR pszPath[MAX_PATH];
GetCurrentDirectory(_countof(pszPath), pszPath);
CString sPath(pszPath);

我的问题的答案是否定的,我认为会是这样,因为CoTaskMemAlloc是一种特殊的内存分配方式。我会坚持常规的做事方式。

int main()
{
    WCHAR* profileRootPath = nullptr;
    HRESULT result = SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, &profileRootPath);
    wcout << profileRootPath;
    CoTaskMemFree(profileRootPath);
    Sleep(10000);
    return 0;
}