我正在尝试创建一个暴露某个API的DLL,因此希望实现一种在DLL边界上复制字符串的安全方法。 DLL实现非常简单 - 返回字符串值的所有函数都有两个参数 - char*
和size_t&
。如果大小足够大,我memcpy
从DLL内到给定指针的字符串内容,将大小设置为实际的大小并返回成功的返回码。如果不是我将大小设置为它应该是什么并返回错误代码。 DLL方面非常简单。
现在更复杂的是 - 如何创建一个很好的模板函数,它给出了一个指向DLL中某个函数的指针,它将执行所有正确的操作来填充std::string
的实例。这就是我的归宿:
template<typename I>
CErrorCode GetStringValue(const I& Instance, CErrorCode(I::*pMethod)(char*, size_t&) const, std::string& sValue)
{
std::string sTemporaryValue;
size_t nValueLength = sTemporaryValue.capacity();
sTemporaryValue.resize(nValueLength);
do
{
auto eErrorCode = (Instance.*pMethod)(const_cast<char*>(sTemporaryValue.c_str()), nValueLength);
if (eErrorCode == CErrorCode::BufferTooSmall)
{
sTemporaryValue.resize(nValueLength);
}
else
{
if (eErrorCode == CErrorCode::NoError)
{
sTemporaryValue.resize(nValueLength);
sValue = std::move(sTemporaryValue);
}
return eErrorCode;
}
}
while (true);
}
所以我做了初始resize
,因为在第一次调用后我不能这样做(从那以后它会擦除内容,因为字符串最初是空的)。但是resize
用零个字符填充字符串,这让我感到不安(我的意思是我知道无论如何我将自己填充)。然后我甚至在成功运行后需要resize
,因为如果长度实际上更小,我需要调整大小。任何建议,如果这可以做得更好我?
答案 0 :(得分:1)
由于您使用的是DLL,我的理解是您使用的是Windows,因此我将建议使用特定于Windows的解决方案。
嗯,在内存中已经通过COM内存分配器和 BSTR
解决了跨越模块边界安全传递字符串的问题。
所以,不是传递一个字符串指针和一个大小指针,而是检查调用者的分配缓冲区是否足够大,如果没有返回所需的大小等,那么返回对我来说似乎要简单得多。来自DLL的BSTR
。
BSTR
是使用COM分配器分配的,因此您可以分配它们并在不同的模块边界上释放它们。
BSTR
周围还有很好的C ++包装类,例如: _bstr_t
或ATL&#39; CComBSTR
。您可以在来电者的网站上使用这些内容。
一旦你有一个BSTR
实例,可能正确地包装在来电者网站的方便的RAII包装中,你就可以轻松地将其转换为std::wstring
。
或者,如果您想使用Unicode UTF-8编码和std::string
,您可以使用{BSTR
的原生UTF-16编码转换为UTF-8 {1}}(this MSDN Magazine article可以派上用场)。
奖金阅读:Eric’s Complete Guide To BSTR Semantics
<强> P.S。强>
如果您不想使用WideCharToMultiByte()
类型,您仍然可以使用COM提供的公共内存分配器:例如您可以使用DLL中的 BSTR
分配您的(UTF-8)字符串内存,并使用 CoTaskMemAlloc()
在来电者处将其释放。网站。