调用 没有问题FormatMessage
。它像宣传的那样工作。但是,您没有传入值 123 ( ERROR_INVALID_NAME
)。ERROR_NO_TOKEN
由于GetLastError
在错误的时间调用,您无意中通过了 1008 ( )。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)
构造另一个临时的。
- c'tor
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))
// ...
(或在if 语句中使用 init语句来限制范围,如果您使用的是 C++17)。无论哪种方式,您的下一个调用必须是GetLastError
捕获最后一个仍然有意义的错误代码。但是,您将该值传递给CWin32FileError
'c'tor,或者它使用的参数类型取决于您。但是您不能依靠该 c'tor 为您捕获最后一个错误代码。