Нет проблем с звонком на 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))
GetWorkingPath()
создает временный CString
экземпляр.
operator+(CString const&, LPCTSTR)
создает еще один временный экземпляр CString
, объединяя оба входа.
operator LPCTSTR()
неявно вызывается для временного объекта, созданного на шаге 2.
CreateDirectory
вызывается и возвращается.
- Важно: Называется деструктор временного объекта, созданного на шаге 2.
- Важно: Называется деструктор временного объекта, созданного на шаге 1.
Шаги 5 и 6 уже являются фатальными и могут изменить последний код ошибки вызывающего потока. И все же, есть еще больше кода, мешающего:
CWin32FileError e(_T("whatever"),
GetWorkingPath() + _T("whatever"));
- Важное замечание:
_T("whatever")
запускает конструктор преобразования CString
(CString(LPCTSTR)
), создавая временный файл.
- Важное замечание:
GetWorkingPath()
создает временный объект, вызывая CString
copy-c'tor.
- Важно:
operator+(CString const&, LPCTSTR)
создает еще один временный объект.
- Наконец-то
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
или какие типы аргументов он использует, зависит от вас. Но вы не можете рассчитывать на то, что этот код не захватит для вас последний код ошибки.