Почему в Microsoft Error Message используется слово «Token»? - PullRequest
0 голосов
/ 22 апреля 2019

Я специально установил неверный путь для вызова CreateDirectory, чтобы мой код обработки исключений выполнялся:

Microsoft Error Text

Я не уверен, что это не по теме, но у вас может быть больше опыта с этим. Почему текст ошибки:

Была сделана попытка сослаться на токен , который не существует.

Почему они используют слово token вместо file или folder ?

Я закрою вопрос, если не по теме.

Возвращаемое значение GetLastError: 123

Согласно здесь :

ERROR_INVALID_NAME

123 (0x7B)

Неверный синтаксис имени файла, имени каталога или метки тома.

Теперь это сообщение имеет смысл. Так почему в моем Windows 10 отображается другое сообщение?

1 Ответ

0 голосов
/ 22 апреля 2019

Нет проблем с звонком на FormatMessage. Это работает как рекламируется. Однако вы не передаете значение 123 (ERROR_INVALID_NAME). Вы проезжаете 1008 (ERROR_NO_TOKEN), случайно, из-за вызова GetLastError в неподходящее время. GetLastError имеет строгое требование:

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

Довольно просто удовлетворить это в C. В C ++ все становится сложнее, со всем невидимым кодом, который генерирует компилятор. Код, о котором идет речь, по-видимому, фиксирует последний код ошибки вызывающего потока только после того, как он введет CWin32FileError c'tor. Уже слишком поздно.

Исходя из предположения, что GetWorkingPath() возвращает CString экземпляр по значению, а CWin32FileError принимает свои аргументы как CString const&, это то, что происходит за сценой:

if (!CreateDirectory(GetWorkingPath() + _T("whatever"), nullptr))
  1. GetWorkingPath() создает временный CString экземпляр.
  2. operator+(CString const&, LPCTSTR) создает еще один временный экземпляр CString, объединяя оба входа.
  3. operator LPCTSTR() неявно вызывается для временного объекта, созданного на шаге 2.
  4. CreateDirectory вызывается и возвращается.
  5. Важно: Называется деструктор временного объекта, созданного на шаге 2.
  6. Важно: Называется деструктор временного объекта, созданного на шаге 1.

Шаги 5 и 6 уже являются фатальными и могут изменить последний код ошибки вызывающего потока. И все же, есть еще больше кода, мешающего:

CWin32FileError e(_T("whatever"),
                  GetWorkingPath() + _T("whatever"));
  1. Важное замечание: _T("whatever") запускает конструктор преобразования CString (CString(LPCTSTR)), создавая временный файл.
  2. Важное замечание: GetWorkingPath() создает временный объект, вызывая CString copy-c'tor.
  3. Важно: operator+(CString const&, LPCTSTR) создает еще один временный объект.
  4. Наконец-то CWin32FileError запускается, предположительно вызывая GetLastError.

Это добавляет еще 3 кандидата (по крайней мере), которые могут изменить последний код ошибки вызывающего потока. Чтобы решить эту проблему, вам нужно убедиться, что абсолютно никакой код не выполняется между неудачным вызовом Windows API и вызовом GetLastError.

Для этого вам придется избавиться от временных данных и перенести захват последнего кода ошибки за пределы CWin32FileError c'tor. Простым решением первого было бы создать имя пути заранее, например,

auto path_name{ GetWorkingPath() + _T("whatever") };
auto path_name_strptr{ path_name.GetString() };
if (!CreateDirectory(path_name_strptr, nullptr))
// ...

(или используйте оператор init в операторе if , чтобы ограничить область действия, если вы используете C ++ 17). В любом случае, ваш следующий вызов должен быть GetLastError, чтобы захватить последний код ошибки, пока он еще значим. Однако вы передаете это значение в c'or CWin32FileError или какие типы аргументов он использует, зависит от вас. Но вы не можете рассчитывать на то, что этот код не захватит для вас последний код ошибки.

...