为什么Microsoft错误消息使用“令牌”一词?

问题描述 投票:0回答:1

我故意为CreateDirectory调用设置一个坏路径,以便执行我的异常处理代码:

Microsoft Error Text

我不确定这是不是主题,但你可能有更多的经验。为什么是错误文本:

尝试引用不存在的令牌。

他们为什么使用令牌而不是文件或文件夹?

如果偏离主题我会关闭这个问题。

GetLastError的返回值是:123

here说:

ERROR_INVALID_NAME

123 (0x7B)

文件名,目录名或卷标语法不正确。

现在这个消息是有道理的。那么为什么我的Windows 10会显示另一条消息?

winapi token getlasterror
1个回答
0
投票

调用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))
  1. GetWorkingPath()构建了一个临时的CString实例。
  2. operator+(CString const&, LPCTSTR)构建另一个临时的CString实例,连接两个输入。
  3. 在步骤2中构造的临时值上隐式调用operator LPCTSTR()
  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 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来捕获你的最后一个错误代码。

© www.soinside.com 2019 - 2024. All rights reserved.