[英]Why Microsoft Error Message uses the word “Token”?
I purposely set a bad path for a CreateDirectory
call so that my exception handling code would execute: 我故意为
CreateDirectory
调用设置一个错误的路径,以便我的异常处理代码将执行:
I am not sure if this is off topic, but you might have more experience with this. 我不确定这是不是主题,但你可能有更多的经验。 Why is the error text:
为什么是错误文本:
An attempt was made to reference a token that does not exist.
尝试引用不存在的令牌 。
Why are they using the word token instead of file or folder ? 他们为什么使用令牌而不是文件或文件夹 ?
I will close the question if off topic. 如果偏离主题我会关闭这个问题。
The return value of GetLastError
is: 123 GetLastError
的返回值是: 123
ERROR_INVALID_NAME
123 (0x7B)
The filename, directory name, or volume label syntax is incorrect.
文件名,目录名或卷标语法不正确。
Now that message makes sense. 现在这个消息是有道理的。 So why is my Windows 10 showing the other message?
那么为什么我的Windows 10会显示另一条消息?
There is no issue with the call to FormatMessage
. 调用
FormatMessage
没有问题。 It works as advertised. 它像宣传的那样工作。 However, you aren't passing in the value 123 (
ERROR_INVALID_NAME
). 但是,您没有传入值123(
ERROR_INVALID_NAME
)。 You are passing 1008 ( ERROR_NO_TOKEN
), by accident, due to calling GetLastError
at the wrong time. 由于在错误的时间调用
GetLastError
,您偶然传递1008( ERROR_NO_TOKEN
)。 GetLastError has a strong requirement: GetLastError有一个强烈的要求:
You should call the
GetLastError
function immediately when a function's return value indicates that such a call will return useful data.当函数的返回值指示此类调用将返回有用数据时,应立即调用
GetLastError
函数。 That is because some functions callSetLastError
with a zero when they succeed, wiping out the error code set by the most recently failed function.这是因为一些函数在成功时调用
SetLastError
为零,消除了最近失败的函数设置的错误代码。
It's fairly straightforward to satisfy this in C. With C++, things get more complicated, with all the invisible code the compiler generates. 在C语言中满足这一点是相当简单的。使用C ++,事情变得更复杂,编译器生成的所有不可见代码。 The code in question apparently captures the calling thread's last error code only after it enters the
CWin32FileError
c'tor. 有问题的代码显然只在它进入
CWin32FileError
c'tor之后才捕获调用线程的最后一个错误代码。 That's too late. 那太晚了。
Based on the assumption that GetWorkingPath()
returns a CString
instance by value, and CWin32FileError
takes its arguments as CString const&
, this is what happens behind the scenes: 基于
GetWorkingPath()
按值返回CString
实例的假设, CWin32FileError
将其参数作为CString const&
,这就是幕后发生的事情:
if (!CreateDirectory(GetWorkingPath() + _T("whatever"), nullptr))
GetWorkingPath()
constructs a temporary CString
instance. GetWorkingPath()
构造一个临时的CString
实例。 operator+(CString const&, LPCTSTR)
constructs yet another temporary CString
instance, concatenating both inputs. operator+(CString const&, LPCTSTR)
构造另一个临时CString
实例,连接两个输入。 operator LPCTSTR()
is implicitly invoked on the temporary constructed in step 2. operator LPCTSTR()
。 CreateDirectory
is called and returns. CreateDirectory
被调用并返回。 Steps 5 and 6 are fatal already, potentially changing the calling thread's last error code. 步骤5和6已经致命,可能会更改调用线程的最后一个错误代码。 And yet, there's even more code getting in the way:
然而,还有更多的代码阻碍了它们:
CWin32FileError e(_T("whatever"),
GetWorkingPath() + _T("whatever"));
_T("whatever")
triggers CString
's conversion constructor ( CString(LPCTSTR)
), producing a temporary. _T("whatever")
触发CString
的转换构造函数( CString(LPCTSTR)
),产生一个临时的。 GetWorkingPath()
constructs a temporary, invoking CString
's copy-c'tor. GetWorkingPath()
构造一个临时的,调用CString
的copy-c'tor。 operator+(CString const&, LPCTSTR)
constructs yet another temporary. operator+(CString const&, LPCTSTR)
构造了另一个临时的。 CWin32FileError
c'tor finally runs, presumably calling GetLastError
. CWin32FileError
c'tor最终运行,大概是调用GetLastError
。 This adds another 3 candidates (at least) that can modify the calling thread's last error code. 这增加了另外3个候选者(至少)可以修改调用线程的最后一个错误代码。 To solve this, you're going to have to make sure, that absolutely no code runs in between a failed Windows API call and the call to
GetLastError
. 要解决这个问题,您必须确保在失败的Windows API调用和对
GetLastError
的调用之间绝对没有代码运行。
To do this, you're going to have to get rid of the temporaries, and move capturing of the last error code outside the CWin32FileError
c'tor. 要做到这一点,你将不得不摆脱临时,并移动
CWin32FileError
c'tor之外的最后一个错误代码。 A simple solution to the former would be to construct the path name up front, eg 对前者的简单解决方案是预先构造路径名称,例如
auto path_name{ GetWorkingPath() + _T("whatever") };
auto path_name_strptr{ path_name.GetString() };
if (!CreateDirectory(path_name_strptr, nullptr))
// ...
(or use an init-statement in the if statement to limit the scope, if you are using C++17). (或者,如果使用的是C ++,则在if语句中使用init 语句来限制范围)。 Either way, your very next call must be
GetLastError
to capture the last error code while it is still meaningful. 无论哪种方式,您的下一个调用必须是
GetLastError
以捕获最后一个错误代码,同时它仍然有意义。 However you pass that value into CWin32FileError
's c'tor, or which argument types it uses, is up to you. 但是,您将该值传递给
CWin32FileError
的c'tor,或者它使用的参数类型取决于您。 But you cannot rely on that c'tor to capture the last error code for you. 但你不能依靠那个c'tor来捕获你的最后一个错误代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.