0

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

微软错误文本

我不确定这是否离题,但您可能对此有更多经验。为什么是错误文本:

试图引用不存在的令牌。

为什么他们使用单词令牌而不是文件文件夹

如果题外话,我会关闭这个问题。

的返回值为GetLastError123

根据这里

ERROR_INVALID_NAME

123 (0x7B)

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

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

4

1 回答 1

0

调用 没有问题FormatMessage。它像宣传的那样工作。但是,您没有传入值 123 ( ERROR_INVALID_NAME)。ERROR_NO_TOKEN由于GetLastError在错误的时间调用,您无意中通过了 1008 ( )。GetLastError有很强的要求:

当函数的返回值表明这样的调用将返回有用的数据时,您应该立即GetLastError调用该函数。这是因为某些函数在成功时调用为零,从而消除了最近失败的函数设置的错误代码。SetLastError

在 C 中满足这一点相当简单。使用 C++,事情变得更加复杂,编译器生成的所有不可见代码。有问题的代码显然仅在它进入CWin32FileErrorc'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. c'torCWin32FileError终于运行了,大概是在调用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 为您捕获最后一个错误代码。

于 2019-04-22T09:39:40.917 回答