Замените to_utf8string, чтобы обеспечить правильную кодировку строк на Windows 7 в C ++ DLL. - PullRequest
0 голосов
/ 03 августа 2020

У меня есть устаревший код C ++, который был написан как dll, который можно вызывать на Windows 10. Новое требование - позволить этой dll правильно работать на более ранних Windows (7 встроенных, опционально XP) . Короче говоря, код должен отображать body ответа REST.

Проблема в том, что при вызове Windows 7 без каких-либо изменений появляются дополнительные (иногда невидимые) символы, особенно в начало отображаемого вывода.

Код ниже является сокращенной версией, и я считаю, что to_utf8string - это root проблемы. Какую еще функцию мне следует использовать, чтобы эта dll работала на Windows 7 должным образом?

const char* foo(const char* param)
{
    web::http::http_response resp = other_foo(param).get();
    std::string utf8Response;

    web::json::value json = resp.extract_json().get();
    utf8Response = utility::conversions::to_utf8string(json.serialize());

    return utf8Response.c_str();
}

Два примера выходных данных на Windows 7:

  1. Должно быть: {"statusCode": 400, example 1

  2. Should be: {"status": пример2

1 Ответ

3 голосов
/ 03 августа 2020

Проблема не имеет ничего общего с кодировкой символов или используемой ОС. Функция возвращает висячий указатель на недопустимую память !

Функция объявляет локальную переменную std::string, которая выходит за пределы области видимости при выходе из функции. Он возвращает указатель на внутренние символьные данные std::string, которые освобождаются при уничтожении std::string.

Чтобы решить эту проблему, функция должна будет динамически возвращать указатель на выделенная память , которую вызывающий абонент может затем освободить (или передать обратно в DLL для освобождения) позже, когда это будет выполнено с использованием данных. Например:

const char* foo(const char* param)
{
    web::http::http_response resp = other_foo(param).get();
    web::json::value json = resp.extract_json().get();
    std::string utf8Response = utility::conversions::to_utf8string(json.serialize());

    // the caller can use CoTaskMemFree() to free this returned memory...
    size_t size = utf8Response.size() + 1; // +1 for null terminator
    char *ptr = static_cast<char*>(CoTaskMemAlloc(size));
    if (ptr)
        std::memcpy(ptr, utf8Response.c_str(), size);
    return ptr;
}
const char* response = foo(param);
if (response) {
    ...
    CoTaskMemFree(response);
}

Или:

const char* foo(const char* param)
{
    web::http::http_response resp = other_foo(param).get();
    web::json::value json = resp.extract_json().get();
    std::string utf8Response = utility::conversions::to_utf8string(json.serialize());

    // the caller must call free_foo_result() to free this memory...
    size_t size = utf8Response.size() + 1; // +1 for null terminator
    char *ptr = new(std::nothrow) char[size];
    if (ptr)
        std::memcpy(ptr, utf8Response.c_str(), size);
    return ptr;
}

void free_foo_result(const char *data)
{
    delete[] data;
}
const char* response = foo(param);
if (response) {
    ...
    free_foo_result(response);
}

Если перезапись EXE для выполнения этих дополнительных вызовов функций не является вариантом, тогда DLL будет должны кэшировать данные JSON, чтобы они могли выжить после return, например:

const char* foo(const char* param)
{
    static thread_local std::string utf8Response;

    web::http::http_response resp = other_foo(param).get();
    web::json::value json = resp.extract_json().get();
    utf8Response = utility::conversions::to_utf8string(json.serialize());

    return utf8Response.c_str();
}
...