Results 1 to 11 of 11

Thread: [RESOLVED] How do I get the description for an HRESULT?

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Aug 2011
    Location
    Palm Coast, FL
    Posts
    544

    Resolved [RESOLVED] How do I get the description for an HRESULT?

    I'm fairly familiar with the Win32 API. Processing errors via Err.LastDLLError (not GetLastError!) and getting the error description via the FormatMessage api works great.

    But the latest routine I've coded uses a Shell API (SHOpenFolderAndSelectItems) which returns an HRESULT. Determining if the HRESULT represents success or failure is easy. What I can't figure out is how to get the description of the error code. It seems that FormatMessage can handle some HRESULTS. But is this the correct way to do this? Is there a function like FormatMessage that is used for HRESULTS?

    Thanks,
    Art

  2. #2
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    554

    Re: How do I get the description for an HRESULT?

    https://en.wikipedia.org/wiki/HRESULT#HRESULT_format
    https://msdn.microsoft.com/en-us/library/cc231198.aspx

    Also check out Winerror.h

    Many HResult errors are user defined so I'm thinking that FormatMessage can only handle common windows errors but I'm not sure of this
    Last edited by Code Dummy; Jul 19th, 2017 at 06:59 PM.

  3. #3
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    6,010

    Re: How do I get the description for an HRESULT?

    I use these two modules for the most coverage I've been able to get. The second one has some overlaps with the first and I haven't cleaned it up, that's why it's in two modules. Use the GetLastError_Msg function, it automatically checks the 2nd module if it doesn't have it.
    Attached Files Attached Files

  4. #4

    Thread Starter
    Fanatic Member
    Join Date
    Aug 2011
    Location
    Palm Coast, FL
    Posts
    544

    Re: How do I get the description for an HRESULT?

    Thanks for the suggestions guys. As a follow-up to my own post, this is what I found:

    Here's a list of all system defined HRESULT values and descriptions:

    https://msdn.microsoft.com/en-us/library/cc704587.aspx

    I could put them all into a module like fafalone does but I don't think I need to. FormatMessage seems to be able to handle these. I passed several of these HRESULTS to FormatMessage and the correct descriptions came out. Note that this was not an exhaustive test. I simply used some HRESULT values the MSDN page listed above to test and all of my tests passed. Based on this sampling, I have confidence that the FormatMessage API has been coded to accept either Win32 or HRESULT input values.

  5. #5
    Member Dragokas's Avatar
    Join Date
    Aug 2015
    Location
    Ukraine
    Posts
    740

    Re: [RESOLVED] How do I get the description for an HRESULT?

    offtopic.
    Here is an addition. List of NTSTATUS error codes I recently "dumped" from MSDN page.
    It is used like:
    Code:
        Dim sFullDescr$
        Debug.Print GetNTStatusText(&HC0000022, sFullDescr)
        Debug.Print sFullDescr
    Attached Files Attached Files
    Malware analyst, VirusNet developer, HiJackThis+ author || my CodeBank works

  6. #6

    Thread Starter
    Fanatic Member
    Join Date
    Aug 2011
    Location
    Palm Coast, FL
    Posts
    544

    Re: [RESOLVED] How do I get the description for an HRESULT?

    Quote Originally Posted by Dragokas View Post
    offtopic.
    Here is an addition. List of NTSTATUS error codes I recently "dumped" from MSDN page.
    Here's an alternate way to handle NTSTATUS errors: The trusty FormatMessage API mentioned earlier can be used for these as well but the NSTATUS error code must be converted to a Win32 error code using this routine:

    Code:
    Private Type OVERLAPPED
        Internal As Long
        InternalHigh As Long
        Offset As Long
        OffsetHigh As Long
        hEvent As Long
    End Type
    
    Private Declare Sub SetLastError Lib "kernel32" (ByVal dwErrCode As Long)
    Private Declare Function GetOverlappedResult Lib "kernel32" (ByVal hFile As Long, lpOverlapped As OVERLAPPED, lpNumberOfBytesTransferred As Long, ByVal bWait As Long) As Long
    
    Private Function NtStatusToWin32Error(NTStatus As Long) As Long
        Dim oldError    As Long
        Dim result      As Long
        Dim br          As Long
        Dim o           As OVERLAPPED
        
        With o
            .Internal = NTStatus
            .InternalHigh = 0
            .Offset = 0
            .OffsetHigh = 0
            .hEvent = 0
        End With
        
        oldError = Err.LastDllError()
        Call GetOverlappedResult(0&, o, br, 0&)
        result = Err.LastDllError()
        SetLastError (oldError)
        
        NtStatusToWin32Error = result
    
    End Function

  7. #7
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,482

    Re: [RESOLVED] How do I get the description for an HRESULT?

    Should prove helpful to others. Plenty of good keywords here to help a Googler find this thread in the future: FormatMessage, System Error, HRESULT, NTSTATUS, VB6.

  8. #8
    Member Dragokas's Avatar
    Join Date
    Aug 2015
    Location
    Ukraine
    Posts
    740

    Re: [RESOLVED] How do I get the description for an HRESULT?

    AAraya, that's interesting convertor. Your code forced me to prove that FormatMessage + (convertion NTStatus -> System Error Code) = Description of NTStatus on MSDN page. The test show me that ~ 30% codes descriptions is identical, ~ 30% have a very close description, rest are wrong or no description.

    dilettante, in such case I also post here FormatMessage:

    Code:
    Option Explicit
    
    Private Declare Function FormatMessage Lib "kernel32.dll" Alias "FormatMessageA" (ByVal dwFlags As Long, lpSource As Long, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, Arguments As Any) As Long
    
    Public Function ErrMessageText(lCode As Long) As String
        Const MAX_PATH As Long = 260
        Const FORMAT_MESSAGE_FROM_SYSTEM    As Long = &H1000&
        Const FORMAT_MESSAGE_IGNORE_INSERTS As Long = &H200
        
        Dim sRtrnCode   As String
        Dim lRet        As Long
    
        sRtrnCode = String$(MAX_PATH, 0&)
        lRet = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS, ByVal 0&, lCode, ByVal 0&, sRtrnCode, MAX_PATH, ByVal 0&)
        If lRet > 0 Then
            ErrMessageText = Left$(sRtrnCode, lRet)
            ErrMessageText = Replace$(ErrMessageText, vbCr, " ")
            ErrMessageText = Replace$(ErrMessageText, vbLf, " ")
        End If
    End Function
    Attached Files Attached Files
    Malware analyst, VirusNet developer, HiJackThis+ author || my CodeBank works

  9. #9

    Thread Starter
    Fanatic Member
    Join Date
    Aug 2011
    Location
    Palm Coast, FL
    Posts
    544

    Re: [RESOLVED] How do I get the description for an HRESULT?

    Quote Originally Posted by Dragokas View Post
    AAraya, that's interesting convertor. Your code forced me to prove that FormatMessage + (convertion NTStatus -> System Error Code) = Description of NTStatus on MSDN page. The test show me that ~ 30% codes descriptions is identical, ~ 30% have a very close description, rest are wrong or no description.
    Dragokas, that's a good test, I'm glad you did that. I assumed that the method I posted was accurate as I had gotten the code from a source I trusted and performed a test on a sampling of values. I see that my methodology was flawed. Perhaps then my findings on using FormatMessage for HRESULT is flawed as well since I likewise tested only a sampling of HRESULTs?

    The safest method may be the one fafalone and others are using of getting a list of all NTStatus and HRESULT errors from MSDN and putting them in a module along with their descriptions. The downside to this approach, as I see it, is the need to keep the error lists updated as they are expanded with new errors.

    On further reflection, another downside to storing all of the errors and their descriptions in a module is that the error messages (for HRESULT & NTStatus) will always be in English. Using FormatMessage they're going to be automatically presented to the user in their system default language. But if it's not reliable, I guess there's not much of an option.
    Last edited by AAraya; Jul 23rd, 2017 at 08:22 PM.

  10. #10

    Thread Starter
    Fanatic Member
    Join Date
    Aug 2011
    Location
    Palm Coast, FL
    Posts
    544

    Re: [RESOLVED] How do I get the description for an HRESULT?

    I found another method of converting NTStatus codes to Win32 errors which is provided by Windows. The function is called RtlNtStatusToDosError() and like the name suggests, it converts the specified NTSTATUS code to its equivalent system error code. The initial results are promising. Here's an updated version of the NtStatusToWin32Error function I posted earlier:

    Code:
    Private Declare Function RtlNtStatusToDosError Lib "ntdll.dll" (ByVal status As Long) As Long
    Private Const ERROR_MR_MID_NOT_FOUND As Long = 317
    
    Private Function NtStatusToWin32Error(NTStatus As Long) As Long
        Dim lngSystemErrCode    As Long
        
        lngSystemErrCode = RtlNtStatusToDosError(NTStatus)
        
        If lngSystemErrCode = ERROR_MR_MID_NOT_FOUND Then
            'no corresponding system error code
            'we'll need to get the error description some other way - perhaps calling out to a module 
            'containing all NTStatus codes/descriptions
        End If
        
        NtStatusToWin32Error = lngSystemErrCode
    End Function
    In my tests, only 9 NTStatus codes did not have a corresponding System Error number.
    Last edited by AAraya; Jul 24th, 2017 at 09:10 AM.

  11. #11
    Member Dragokas's Avatar
    Join Date
    Aug 2015
    Location
    Ukraine
    Posts
    740

    Re: [RESOLVED] How do I get the description for an HRESULT?

    AAraya, nice finding. It looks much much better.

    In my tests, only 9 NTStatus codes did not have a corresponding System Error number.
    10, as I can see on Win10. MSDN descriptions for them are:
    -1073741684 {EXCEPTION} Array bounds exceeded.
    -1073741683 {EXCEPTION} Floating-point denormal operand.
    -1073741682 {EXCEPTION} Floating-point division by zero.
    -1073741681 {EXCEPTION} Floating-point inexact result.
    -1073741680 {EXCEPTION} Floating-point invalid operation.
    -1073741679 {EXCEPTION} Floating-point overflow.
    -1073741678 {EXCEPTION} Floating-point stack check.
    -1073741677 {EXCEPTION} Floating-point underflow.
    -1073741676 {EXCEPTION} Integer division by zero.
    -1073741674 {EXCEPTION} Privileged instruction.
    Other differences sometimes is very fun to read. Mostly it's the same meaning with another words like:
    MSDN:
    -1073741675 {EXCEPTION} Integer overflow.

    When RtlNtStatusToDosError + FormatMessage:
    -1073741675 Arithmetic result exceeded 32 bits.

    So, it's almost match.

    I also agree, that full listing of error codes descriptions in program has disadvantages:
    1. No local language translation
    And one more:
    2. Big size (+500 KB) in compiled exe + It almost definitely takes up one more bas-module in project.
    Attached Files Attached Files
    Malware analyst, VirusNet developer, HiJackThis+ author || my CodeBank works

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width