DLL边界上的安全字符串复制

时间:2016-10-05 14:12:26

标签: c++ dll stdstring

我正在尝试创建一个暴露某个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,因为如果长度实际上更小,我需要调整大小。任何建议,如果这可以做得更好我?

1 个答案:

答案 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() 在来电者处将其释放。网站。