我知道NTSTATUS,我将在特定错误的情况下获得,但我得到了hresult,而不是来自pinvoke的ntstatus.那么如何将特定的NTSTATUS值转换为Hresult.
我试过没有成功:
class Program
{
private const int FacilityNtBit = 0x10000000;
//#define STATUS_DUPLICATE_OBJECTID ((NTSTATUS)0xC000022AL)
private const int STATUS_DUPLICATE_OBJECTID = unchecked((int) (0xC000022A));
// HResult that is returned for the STATUS_DUPLICATE_OBJECTID
private const int CorrectHrStatusDuplicateObjectid = -2147019886;
static void Main(string[] args)
{
int res = HRESULT_FROM_NT(STATUS_DUPLICATE_OBJECTID);
Debug.Assert(res == CorrectHrStatusDuplicateObjectid, "Must be the same");
}
private static int HRESULT_FROM_NT(int ntStatus)
{
//#define HRESULT_FROM_NT(x) ((HRESULT) ((x) | FACILITY_NT_BIT))
return ntStatus | FacilityNtBit;
}
}
Run Code Online (Sandbox Code Playgroud)
NTSTATUS你有0xC000022A: STATUS_DUPLICATE_OBJECTID- 尝试在索引中插入ID失败,因为ID已在索引中.)
HRESULT你想0x80071392:
FACILITY_WIN32- 保留此区域以将未修改的错误代码映射到HRESULT.)ERROR_OBJECT_ALREADY_EXISTS- 对象已经存在.)问题是同一错误有多种表示形式:
0xC000022A50100xD000022A 将NSTATUS转换为HRESULT)0x80071392 将Win32错误转换为HRESULT)
并非所有NTSTATUS代码都可以转换为Win32.在那种情况下,试图通过RtlNtstatusToDosError将给你错误代码ERROR_MR_MID_NOT_FOUND:
系统无法在%2的消息文件中找到消息号0x%1的消息文本.
这就是为什么最好保留真正的错误信息.
我假设遇到的真正问题是如何将NTSTATUS一个错误消息转换为可以显示给用户的错误消息.为此您需要Microsoft知识库文章:
KB259693 - 如何将NTSTATUS错误代码转换为消息字符串
大多数内核模式API函数返回NTSTATUS值.要使用FormatMessage API函数将这些状态值转换为消息,必须在参数列表中引用NtDLL.dll模块.
Run Code Online (Sandbox Code Playgroud)void DisplayError(DWORD NTStatusMessage) { LPVOID lpMessageBuffer; HMODULE Hand = LoadLibrary("NTDLL.DLL"); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, Hand, Err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMessageBuffer, 0, NULL ); // Now display the string. // Free the buffer allocated by the system. LocalFree( lpMessageBuffer ); FreeLibrary(Hand); }
RtlNtStatusToDosError(Status)作为将错误代码转换NTSTATUS为 Win32 错误代码的替代方法,我滥用了GetOverlappedResult()(来自 kernel32.dll),如下所示:
DWORD
ConvertNtStatusToWin32Error(NTSTATUS ntstatus)
{
DWORD oldError;
DWORD result;
DWORD br;
OVERLAPPED o;
o.Internal = ntstatus;
o.InternalHigh = 0;
o.Offset = 0;
o.OffsetHigh = 0;
o.hEvent = 0;
oldError = GetLastError();
GetOverlappedResult(NULL, &o, &br, FALSE);
result = GetLastError();
SetLastError(oldError);
return result;
}
Run Code Online (Sandbox Code Playgroud)
然后可以将 Win32 错误代码转换为HRESULT使用HRESULT_FROM_WIN32(error).
本机操作系统错误代码到 winapi 层错误代码的映射并非易事。5010 和 0xc000022a 之间没有任何对应关系。使用的心理图像是隐藏在 ntdll.dll 中的一个巨大的 switch 语句,它可以从一个转换到另一个。 微软不情愿地公开了它,你通常必须经历重重困难才能使用它。实际上,pinvoke 代码更容易,因为它已经使用 GetProcAddress() 来查找导出的函数。
但是,只要您进行 winapi 调用,您就应该只期望得到 winapi 错误代码,而不要尝试自己翻译它。它可以包含在 HRESULT 中,即 0x80070000 + 错误。本机操作系统错误代码有时确实会渗透,特别是对于 SEH 异常代码,但总是很容易识别。
如果您提到了您尝试使用的 winapi 函数,这个问题会更容易准确回答。
这有效:
internal static class NativeMethods
{
[DllImport("ntdll.dll")]
public static extern int RtlNtStatusToDosError(int status);
}
internal static class Program
{
//#define STATUS_DUPLICATE_OBJECTID ((NTSTATUS)0xC000022AL)
private const int STATUS_DUPLICATE_OBJECTID = unchecked((int) (0xC000022A));
// HResult that is returned for the STATUS_DUPLICATE_OBJECTID
private const int CorrectHrStatusDuplicateObjectid = -2147019886;
private const int HresultWin32Prefix = unchecked((int)0x80070000);
static void Main(string[] args)
{
int code = NativeMethods.RtlNtStatusToDosError(STATUS_DUPLICATE_OBJECTID);
int hresult = code | HresultWin32Prefix;
Debug.Assert(hresult == CorrectHrStatusDuplicateObjectid, "Must be the same");
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3593 次 |
| 最近记录: |