Назначение CString меняет значение GetLastError () - PullRequest
0 голосов
/ 11 июня 2018

Я использую MFC CString объекты для строк.У меня проблема, из-за которой установка CString приводит к неожиданному установлению GetLastError().

Ниже приведена упрощенная версия проблемы, в которой показана проблема:

CString csTest;
DWORD dwLastError = 0;

SetLastError(0);
csTest = _T("test");
dwLastError = GetLastError();  // dwLastError is still 0, as expected
csTest = "another test";  // Not using TCHAR
dwLastError = GetLastError(); // dwLastError now set to 122, "The data area passed to a system call is too small."

Я могу воспроизвести эту проблему с помощью Visual Studio 2015, создав новый проект MFC (на основе диалога), идобавив этот код в функцию OnInitDialog() диалогового окна, которое он создал.

Я знаю, что первая строка - это TCHAR, которая по умолчанию в этом проекте будет WCHAR.Таким образом, кажется, что оператор присваивания CString для char* вызывает проблему.

Есть ли способ исправить это?Способ получить предупреждения компилятора, чтобы сообщить мне о назначении char* вместо WCHAR*?Я думал, что раньше он выдавал предупреждения / ошибки для этого в некоторых предыдущих версиях Visual Studio, но сейчас, похоже, этого не происходит, так что, возможно, я запоминаю.

Ответы [ 2 ]

0 голосов
/ 12 июня 2018

Вы можете отключить неявные узко-широкие преобразования, определив макрос _CSTRING_DISABLE_NARROW_WIDE_CONVERSION, поскольку задокументировано .

Но это только поможет вам обойти проблему real : Вы просто звоните GetLastError слишком поздно.Его возвращаемое значение будет действительным, пока вы не вызовете другой вызов.Только не делайте этого.

Теперь, даже если вам удастся предотвратить какие-либо преобразования, реализация CString все равно должна выделить память.Когда вам не повезет, operator new (который вызывает malloc) придется обратиться к функциям управления памятью ОС.

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

0 голосов
/ 11 июня 2018

При назначении ANSI CStringW вызывается WinAPI MultiByteToWideChar.Это похоже на следующее:

csTest = "a"; // <- step in to this line with debugger
->
wchar_t *buf = new wchar_t[10];

MultiByteToWideChar(CP_ACP, 0, "a", -1, buf, 1); 
//Error 122, ERROR_INSUFFICIENT_BUFFER
//MultiByteToWideChar is expecting 2, not 1, for len

DWORD err = GetLastError();
delete[]buf;

Проблема возникает из-за того, что CString использует длину "a" и не учитывает нулевой символ.MultiByteToWideChar устанавливает ошибку.

CString позже исправляет проблему, но GetLastError все еще установлен.

Просто используйте csTest = L"a";, чтобы избежать необходимости преобразования.Или csTest = CA2W("a");

В противном случае GetLastError не следует использовать таким образом.Используйте GetLastError сразу после сбоя функции WinAPI.

Тестирование:

#include <Windows.h>
#include <AtlStr.h>

int main()
{
    DWORD err;
    CStringW str;

    wchar_t *buf = new wchar_t[10];
    int len = MultiByteToWideChar(CP_ACP, 0, "a", 1, NULL, 0);
    MultiByteToWideChar(CP_ACP, 0, "a", -1, buf, len);
    err = GetLastError();
    printf("MultiByteToWideChar error %d\n", err);
    delete[]buf;

    //Below is wrong usage of GetLastError(), it's only for this discussion...
    SetLastError(0);
    str = "a";
    err = GetLastError();
    printf("assignment operator error %d\n", err);

    SetLastError(0);
    str = CA2W("12345");
    err = GetLastError();
    printf("CA2W error %d\n", err); 

    return 0;
}

Вывод:

MultiByteToWideChar error 122
assignment operator error 122
CA2W error 0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...