我故意为CreateDirectory
调用设置一个坏路径,以便执行我的异常处理代码:
我不确定这是不是主题,但你可能有更多的经验。为什么是错误文本:
尝试引用不存在的令牌。
他们为什么使用令牌而不是文件或文件夹?
如果偏离主题我会关闭这个问题。
GetLastError
的返回值是:123
据here说:
ERROR_INVALID_NAME
123 (0x7B)
文件名,目录名或卷标语法不正确。
现在这个消息是有道理的。那么为什么我的Windows 10会显示另一条消息?
调用FormatMessage
没有问题。它像宣传的那样工作。但是,您没有传递值123(ERROR_INVALID_NAME
)。由于在错误的时间打电话给ERROR_NO_TOKEN
,你偶然通过了1008(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()
。CreateDirectory
被召唤并返回。步骤5和6已经致命,可能会更改调用线程的最后一个错误代码。然而,还有更多的代码阻碍了它们:
CWin32FileError e(_T("whatever"),
GetWorkingPath() + _T("whatever"));
_T("whatever")
触发CString
的转换构造函数(CString(LPCTSTR)
),产生一个临时的。GetWorkingPath()
构建了一个临时的,调用CString
的copy-c'tor。operator+(CString const&, LPCTSTR)
构建了另一个临时性的。CWin32FileError
c'tor终于跑了,大概是叫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 statement中的init语句来限制范围,如果你使用的是C ++ 17)。无论哪种方式,你的下一个调用必须是GetLastError
来捕获最后的错误代码,而它仍然有意义。但是,您将该值传递给CWin32FileError
的c'tor,或者它使用的参数类型取决于您。但你不能依靠那个c'tor来捕获你的最后一个错误代码。