פענוח קודי שגיאה ב-Windows — שלוש השכבות Win32, HRESULT ו-NTSTATUS

· עודכן בתאריך: · · Windows, קודי שגיאה, HRESULT, NTSTATUS, Win32 API, פתרון תקלות, דיבוג, פיתוח Windows

היסטוריית עדכונים (גרסה ראשונה, פורסמה בתאריך 20 Aug 2026)
פרסום ראשון
לצטט את המאמר הזה(DOI: 10.5281/zenodo.22176039)

מאמר זה מאוחסן בארכיון Zenodo. להלן גם ה-DOI שתמיד מפנה לגרסה האחרונה וגם ה-DOI המקובע לגרסה שאתם קוראים.

Go Komura (2026). פענוח קודי שגיאה ב-Windows — שלוש השכבות Win32, HRESULT ו-NTSTATUS. KomuraSoft LLC. https://doi.org/10.5281/zenodo.22176039 https://comcomponent.com/he/blog/windows-error-codes-win32-hresult-ntstatus/

DOI (הגרסה האחרונה)
10.5281/zenodo.22176039
DOI (הגרסה הזו)
10.5281/zenodo.22176040

“על מסך האפליקציה הופיעה השגיאה 0x80004005. מה זה אומר?” — בייעוץ troubleshooting, זו שאלה קלאסית. מי שהדביק את המספר מתיבת השגיאה ישר בחיפוש וקיבל ים של מאמרים לא קשורים — כשל של Windows Update, תיקייה משותפת שלא מתחברת, runtime error של VBA, כשל בחיבור ל-database — והתבלבל עוד יותר, לא לבד בזה.

זה קורה כי 0x80004005 (E_FAIL) הוא קוד גנרי שאומר רק “כישלון לא מוגדר”. אותו קוד משמש בהמון מצבים, ולכן חיפוש לפי הקוד בלבד לא מגיע לסיבה. לעומת זאת, קוד כמו 0x80070005 אפשר לפרק תוך שניות עוד לפני החיפוש, אם מכירים את המבנה: “שגיאת Win32 מספר 5 = הגישה נדחתה, עטופה כ-HRESULT”.

מסיבות היסטוריות, ל-Windows יש שלוש שכבות של קודי שגיאה — קודי שגיאת Win32, HRESULT ו-NTSTATUS — עם המרות ביניהן. ברגע שהמבנה ברור, אפשר לקבוע לבד מאיזו שכבה הגיע הקוד ומי החזיר אותו, ומה הקוד האמיתי מאחוריו, והשלב הראשון בחקירה מתקצר משמעותית.

המאמר מיועד לאנשי IT בארגונים קטנים ובינוניים ולמפתחי אפליקציות Windows. הוא עובר על איך מבחינים ומפרקים את שלוש המערכות, על הקשר ל-exceptions ב-.NET, ועל חיפוש מעשי עם err.exe ו-PowerShell — לפי Microsoft Learn ולפי המפרט שפורסם [MS-ERREF], נכון לאוגוסט 2026.

1. השורה התחתונה קודם

  • לקודי שגיאה ב-Windows יש בעיקר שלוש מערכות. קודי שגיאת Win32 (המספר העשרוני הקטן ש-GetLastError מחזיר), HRESULT (הקוד בן 32 bit מאז COM; hex שמתחיל ב-0x8, או decimal שלילי), ו-NTSTATUS (קודי שכבת ה-kernel; שגיאות מתחילות ב-0xC).123
  • Decimal ו-hex הם ייצוגים שונים של אותו קוד. “שגיאה 5”, “0x5” ו”ה-16 bits הנמוכים של 0x80070005” כולם מצביעים על ERROR_ACCESS_DENIED (הגישה נדחתה).1
  • 0x8007xxxx הוא Win32 error שעטפו מחדש. זה קוד שגיאת Win32 שמאוחסן ב-HRESULT עם FACILITY_WIN32 (7); ממירים את ה-16 bits הנמוכים ל-decimal ומקבלים את הקוד האמיתי. זה ה-pattern החשוב ביותר בקריאת קודי שגיאה.45
  • 0x80004005 (E_FAIL) אינו קוד סיבה. הוא אומר “Unspecified failure” ואין בו מידע נוסף. במקום לחפור בקוד הזה, בודקים את ה-context של המקור ואת הלוגים שנלווים אליו.6
  • Decimal שלילי (2147467259- וכדומה) הוא HRESULT. ה-most significant bit מתוך 32 (failure bit) דלוק, ולכן בתצוגה עם סימן הערך שלילי. ממירים ל-hex ואז קוראים.2
  • ערך בן 8 ספרות שמתחיל ב-0xC הוא NTSTATUS. 0xC0000005 (access violation) ו-0xC0000135 (DLL not found) חוזרים כל הזמן ב-Event Log וב-dumps ברגע קריסה. אין להם קשר לשגיאת Win32 מספר 5.7
  • לאותו קוד יש משמעות שונה לפי ה-context. הסיבה לשגיאה 5 יכולה להיות ACL, elevation, אנטי-וירוס, קובץ תפוס ועוד, ו”הקובץ לא נמצא” של שגיאה 2 הוא לעיתים קרובות DLL תלויה. תמיד קוראים את משמעות הקוד יחד עם איזה API נכשל מול מה.1
  • כלי ההמרה והחיפוש כבר שם. certutil -error ו-net helpmsg מובנים ב-Windows; Win32Exception ב-PowerShell מחזיר את ההודעה; על מכונת פיתוח — err.exe (Microsoft Error Lookup Tool); בניתוח dump — !error של WinDbg.8910
  • ב-.NET, HRESULT ממופה לסוג exception. HRESULT מוכר הולך לסוג המתאים (E_ACCESSDENIED → UnauthorizedAccessException וכדומה); לא מוכר הופך ל-COMException; הערך המקורי נשאר ב-Exception.HResult.11

במשפט אחד, תבנית החקירה של קוד שגיאה ב-Windows היא “ליישר את הייצוג ל-hex → לקבוע מאיזו שכבה הקוד → לפרק ולהוציא את הקוד האמיתי → לקרוא אותו יחד עם ה-context”.

2. ב-Windows יש שלוש מערכות קודי שגיאה

קודם כל, המפה הכללית. קודי שגיאה ב-Windows מתפצלים בעיקר לשלוש המערכות הבאות, לפי השכבה שמחזירה אותם.

מערכת מי מחזיר בעיקר איך זה נראה בדרך כלל דוגמה
קוד שגיאת Win32 Win32 API (GetLastError), exit code של פקודה מספר עשרוני קטן (0–15999) 5 = ERROR_ACCESS_DENIED
HRESULT רכיב COM, ה-shell, installer, הרבה frameworks hex בן 8 ספרות שמתחיל ב-0x8, או decimal שלילי 0x80004005 = E_FAIL
NTSTATUS kernel, driver, native API (ntdll) שגיאות הן hex בן 8 ספרות שמתחיל ב-0xC 0xC0000005 = STATUS_ACCESS_VIOLATION

היסטורית הן נערמו בסדר הזה: קודי שגיאת Win32 שירשו מספרי שגיאה של MS-DOS, NTSTATUS שה-NT kernel משתמש בו internally, ו-HRESULT שתוכנן עם כניסת COM כדי “לארוז success/failure ומקור ב-32 bit”. ב-Windows של היום זרימת ההמרה יומיומית: ה-kernel מחזיר NTSTATUS, Win32 subsystem ממיר אותו לקוד שגיאת Win32, ושכבת COM עוטפת אותו הלאה כ-HRESULT.124

זרימת ההמרה בין שלוש המערכותWin32 subsystem ממיר NTSTATUS שה-kernel החזיר לקוד שגיאת Win32, ושכבת COM עוטפת אותו הלאה כ-HRESULTWin32 subsystem ממירהשכבת COM עוטפתkernel ו-driversNTSTATUS (שגיאות 0xC…)קוד שגיאת Win32 (5 וכדומה)HRESULT (0x8007xxxx)

איור 1: זרימת ההמרה בין השכבות. NTSTATUS של ה-kernel הופך לשגיאת Win32, ואז נעטף הלאה כ-HRESULT.

2.1. להתרגל לעבור בין decimal ל-hex

לפני שמבחינים בין שלוש המערכות צריך לדעת שאותו קוד מוצג לפעמים כ-decimal ולפעמים כ-hex, לפי המצב.

  • “שגיאה 5”, “קוד שגיאה: 0x5” → אותו ERROR_ACCESS_DENIED
  • “שגיאה 1223”, “0x4C1” → אותו ERROR_CANCELLED
  • “0x80070005”, “2147024891-“ → אותו HRESULT

ב-PowerShell ההמרה היא שורה אחת.

# Decimal → hex
'0x{0:X8}' -f 1223          # 0x000004C1
'0x{0:X8}' -f -2147024891   # 0x80070005 (negative = HRESULT to hex)

# Hex → decimal
0x4C1                        # 1223

כשרואים decimal שלילי שמתחיל ב-“214…-“, ממירים מיד ל-hex. זה לבד חוסך הרבה בלבול בכניסה לחקירה.

שלושה מראים של אותו קודשגיאה עשרונית 5, hex 0x5 וה-16 bits הנמוכים של 0x80070005 כולם מצביעים על אותו ERROR_ACCESS_DENIEDייצוג עשרוני: שגיאה 5ERROR_ACCESS_DENIEDייצוג hex: 0x5ה-16 bits הנמוכים של 0x80070005ייצוג שונה, אותו קוד

איור 2: decimal, hex וה-16 bits הנמוכים של HRESULT הם רק ייצוגים שונים של אותו קוד.

3. קודי שגיאת Win32 —‏ GetLastError ו-FORMAT_MESSAGE

3.1. ההתנהגות הבסיסית של GetLastError

הרבה Win32 APIs כמו CreateFile ו-RegOpenKeyEx מסמנים כישלון ב-return value (FALSE, NULL, INVALID_HANDLE_VALUE וכדומה), ושומרים את קוד השגיאה המפורט ב-last-error code שמוחזק per-thread. הקורא שולף אותו ב-GetLastError מיד אחרי שווידא שהקריאה נכשלה.13

יש שתי אזהרות מעשיות.13

  1. קוראים מיד אחרי הכישלון. אם מכניסים באמצע קריאת API אחרת (פונקציית לוג, למשל), הקריאה הזו יכולה לדרוס את ה-last-error code.
  2. לא סומכים על הערך בהצלחה. חלק מה-APIs מאפסים את ה-last-error code ל-0 בהצלחה; חלק לא נוגעים בו. הכלל: קודם לוודא כישלון לפי ה-return value, ורק אז לקרוא.
לקרוא GetLastError מיד אחרי כישלוןאחרי שווידאים כישלון לפי ה-return value, שולפים את ה-last-error code ב-GetLastError מיד, בלי להכניס קריאת API אחרתWin32 APIAppWin32 APIAppAPI אחר באמצע יכול לדרוסקריאת CreateFilereturn value של כישלוןGetLastErrorקוד 5

איור 3: קוראים את ה-last-error code מיד אחרי כישלון. קריאת API אחרת באמצע יכולה לדרוס אותו.

כדי לקבל מחרוזת הודעה מהקוד, משתמשים ב-FormatMessage עם הדגל FORMAT_MESSAGE_FROM_SYSTEM.1

#include <windows.h>
#include <stdio.h>

void PrintLastError(const wchar_t* apiName)
{
    DWORD code = GetLastError();   // Call immediately after failure (do not insert another API)
    wchar_t message[512] = L"";
    FormatMessageW(
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        nullptr, code, 0, message, 512, nullptr);
    wprintf(L"%s failed: %lu (0x%08lX) %s", apiName, code, code, message);
}

אם משאירים בלוג של האפליקציה גם decimal, גם hex וגם את טקסט ההודעה, כמו כאן, החקירה אחר כך מתקצרת משמעותית.

לשלוף הודעה מהקוד ולהשאיר בלוגמעבירים את הדגל FORMAT_MESSAGE_FROM_SYSTEM ל-FormatMessage כדי לקבל את מחרוזת ההודעה של קוד השגיאה, ומשאירים בלוג decimal, hex וטקסטקוד שגיאה (דוגמה: 5)קבלת המחרוזת ב-FormatMessageטקסט ההודעהרישום בלוגלכתוב decimal, hex וטקסט יחד

איור 4: ממירים קוד שגיאה למחרוזת הודעה ב-FormatMessage, ומשאירים בלוג decimal, hex וטקסט יחד.

3.2. קודים נפוצים שחוזרים שוב ושוב בשטח

קודי שגיאת Win32 מוגדרים בטווח 0–15999, וב-Microsoft Learn יש רשימה מלאה.1 מתוכם, אלה שפוגשים שוב ושוב בחקירת תקלות:

עשרוני hex symbol משמעות
2 0x2 ERROR_FILE_NOT_FOUND הקובץ שצוין לא נמצא
3 0x3 ERROR_PATH_NOT_FOUND הנתיב שצוין לא נמצא
5 0x5 ERROR_ACCESS_DENIED הגישה נדחתה
32 0x20 ERROR_SHARING_VIOLATION process אחר משתמש בקובץ, אי אפשר לגשת
87 0x57 ERROR_INVALID_PARAMETER הפרמטר שגוי
122 0x7A ERROR_INSUFFICIENT_BUFFER ה-buffer שהועבר קטן מדי
998 0x3E6 ERROR_NOACCESS גישה לא חוקית לכתובת זיכרון
1223 0x4C1 ERROR_CANCELLED המשתמש ביטל את הפעולה

מתוכם, 998 (ERROR_NOACCESS) אינו “הגישה נדחתה” אלא הייצוג של Win32 ל-access violation בזיכרון — הצורה של NTSTATUS STATUS_ACCESS_VIOLATION אחרי המרה לשכבת Win32. לא להתבלבל עם המספר 5. גם 1223 (ERROR_CANCELLED) הוא קוד שמופיע כשהמשתמש בוחר “לא” בתיבת ה-UAC elevation, למשל — יותר “בוטל” מאשר שגיאה.

שגיאות 998 ו-5 הן דברים שונים998 היא access violation בזיכרון, access violation של NTSTATUS שהומרה לשכבת Win32, ושונה במשמעות מ-5 שמייצגת הגישה נדחתההומר לשכבת Win32NTSTATUS 0xC0000005שגיאה 998 (ERROR_NOACCESS)המשמעות היא access violation בזיכרוןשגיאה 5 (הגישה נדחתה)בעיית הרשאות. דבר אחר מ-998

איור 5: שגיאה 998 היא access violation של NTSTATUS שהומרה לשכבת Win32, דבר אחר מדחיית-הגישה 5.

3.3. לאותו קוד יש משמעות שונה לפי ה-context

חשוב יותר מלשנן את טבלת הקודים הנפוצים הוא להבין שקוד שגיאה אומר רק את סוג הכישלון.

  • שגיאה 5 (הגישה נדחתה): רשימת הסיבות האפשריות רחבה — חסר ACL ב-NTFS, כתיבה לאזור מוגן בלי הרשאות Administrator, חסימה של אנטי-וירוס או AppLocker, הרשאות חסרות ל-service account וכן הלאה.
  • שגיאה 2 (הקובץ לא נמצא): לא בהכרח הקובץ שהמשתמש ציין. DLL תלויה שה-EXE ניסה לטעון במרומז, קובץ הגדרות שנראה במקום הלא נכון בגלל Registry redirect (32-bit/64-bit), נתיב שה-environment variable שלו לא התרחב — “איזה קובץ” לא נמצא לא רואים מהקוד.
  • שגיאה 32 (sharing violation): השאלה האמיתית היא “איזה process מחזיק את הקובץ”, אבל הקוד לא אומר את זה.
הסיבה לשגיאה 5 נקבעת לפי ה-contextגם לאותה דחיית גישה יש כמה סיבות אפשריות כמו ACL חסר או היעדר הרשאות Administrator, וצריך לזהות איזה API נכשל מול מהשגיאה 5 (הגישה נדחתה)ACL חסראין הרשאות Administratorחסימה של מוצר אבטחההרשאות service נמוכותProcmon: היעד שנכשל

איור 6: הקוד אומר רק את סוג הכישלון. לשגיאה 5 יש כמה סיבות אפשריות, וצריך לזהות את היעד.

הכלי שמראה בפועל “איזה API, מול איזה object name, החזיר איזו תוצאה” הוא Process Monitor. השימוש בו מפורט ב”מדריך מעשי ל-Process Monitor (ProcMon)”. חיפוש משמעות קוד השגיאה וזיהוי היעד שנכשל הולכים יחד.

4. HRESULT — איך לקרוא את המבנה הארוז ב-32 bit

4.1. פריסת ה-bits

HRESULT הוא פורמט שמכניס success/failure, מקור וקוד פירוט לערך 32-bit אחד. המפרט שפורסם [MS-ERREF] מגדיר אותו בפריסה הבאה.2

מיקום ה-bit שם משמעות
31 S Severity. 0 = success, 1 = failure
30 R reserved (חלק מ-severity כשממפים NTSTATUS)
29 C Customer bit. 1 פירושו קוד שהוגדר על ידי מי שאינו Microsoft
28 N 1 פירושו ערך NTSTATUS שממופה למרחב HRESULT
27 X reserved (0)
26–16 Facility קוד facility שמציין את המקור (11 bits)
15–0 Code קוד פירוט בתוך ה-facility (16 bits)

כש-S-bit הגבוה ביותר הוא 1, כלומר HRESULT שה-hex שלו מתחיל ב-0x8 ומעלה הוא כישלון. תצוגה כ-signed 32-bit integer הופכת אותו לשלילי — זה המקור של ה-“214…-“ שהוזכר קודם.

הקשר בין S-bit לתצוגה שליליתHRESULT של כישלון מדליק את S-bit הגבוה ביותר ל-1, ולכן ב-hex הוא מתחיל ב-0x8 ומעלה, וכ-signed 32-bit integer הוא שליליS-bit = 1 (כישלון)ה-hex מתחיל ב-0x8 ומעלהתצוגה עם סימן יוצאת שליליתכשרואים שלילי, ממירים ל-hex וקוראים

איור 7: HRESULT של כישלון מתחיל ב-0x8 ומעלה כי S-bit הוא 1, ובתצוגה עם סימן הוא שלילי.

ערכי Facility נפוצים הם אלה.5

Facility ערך מראה ב-hex משמעות
FACILITY_NULL 0 0x8000xxxx קודים משותפים רחבים (E_FAIL, E_UNEXPECTED וכדומה)
FACILITY_RPC 1 0x8001xxxx מקור RPC
FACILITY_ITF 4 0x8004xxxx שגיאה מוגדרת-interface (המשמעות תלויה ב-interface)
FACILITY_WIN32 7 0x8007xxxx קוד שגיאת Win32 עטוף
FACILITY_WINDOWS 8 0x8008xxxx interfaces נוספים שהוגדרו ב-Microsoft

4.2. פירוק 0x80004005 ו-0x80070005

נפרק אותם בפועל.

עבור 0x80004005: S=1 (כישלון), Facility=(0x80004005 » 16) & 0x7FF = 0 (FACILITY_NULL), Code=0x4005. זה קוד FACILITY_NULL גנרי, מוגדר כ-E_FAIL “Unspecified failure”.6 כלומר הקוד הזה נושא רק את המשמעות “כישלון שאי אפשר לדווח עליו בפירוט”. כשרואים 0x80004005, מפסיקים לחפור בקוד עצמו, ומעבירים את החקירה ל”איזה רכיב החזיר” ו”יש פירוט ב-Event Log או בלוג האפליקציה באותו זמן”.

עבור 0x80070005: S=1, Facility=7 (FACILITY_WIN32), Code=0x0005=5. רואים שזה שגיאת Win32 מספר 5 (ERROR_ACCESS_DENIED) עטופה כ-HRESULT. הכינוי E_ACCESSDENIED הוא בפועל אותו ערך.6

גם לאותה “הגישה נדחתה”, 0x80070005 הוא עטיפה של כישלון קונקרטי שקרה בשכבת Win32, וכמות המידע שונה לגמרי מ-0x80004005.

פירוק 0x80004005 ו-0x800700050x80004005 הוא הקוד הגנרי E_FAIL של FACILITY_NULL, בלי פירוט, ויש לעבור לחקירת context; 0x80070005 הוא FACILITY_WIN32 ואפשר לקרוא אותו כעטיפה של שגיאת Win32 מספר 5, הגישה נדחתה0x80004005Facility=0 (FACILITY_NULL)Code=0x4005 → E_FAILכישלון לא מוגדר. הלאה לחקירת context0x80070005Facility=7 (FACILITY_WIN32)Code=0x0005 → 5ERROR_ACCESS_DENIED

איור 8: גם אותו “כישלון” — אחרי פירוק כמות המידע שונה. מ-0x80070005 אפשר להגיע לשגיאת Win32 מספר 5.

4.3. ה-pattern החשוב ביותר: 0x8007xxxx = HRESULT_FROM_WIN32

כדי להעביר כישלון משכבה תחתונה שיכולה להחזיר רק קוד שגיאת Win32 לשכבה עליונה שמחזירה HRESULT (מתודת COM או ה-.NET runtime), winerror.h מספק את המאקרו HRESULT_FROM_WIN32.4 ההתנהגות: “לשמור את קוד שגיאת Win32 ב-16 bits הנמוכים, לשים Facility ל-FACILITY_WIN32 (7), ולהדליק את S-bit ל-1”.

איך HRESULT_FROM_WIN32 עובדשומרים את קוד שגיאת Win32 ב-16 bits הנמוכים, שמים Facility ל-7 ואת S-bit ל-1, ומרכיבים HRESULT 0x8007xxxxקוד שגיאת Win32 (דוגמה: 5)שמירה ב-16 bits הנמוכיםFacility מוגדר ל-7S-bit מוגדר ל-10x80070005

איור 9: HRESULT_FROM_WIN32 שומר את שגיאת Win32 ב-16 bits הנמוכים ומגדיר Facility=7 ואת S-bit.

ERROR_ACCESS_DENIED (5)        --HRESULT_FROM_WIN32-->  0x80070005
ERROR_SHARING_VIOLATION (32)   --HRESULT_FROM_WIN32-->  0x80070020
ERROR_INVALID_PARAMETER (87)   --HRESULT_FROM_WIN32-->  0x80070057 (= E_INVALIDARG)
ERROR_OUTOFMEMORY (14)         --HRESULT_FROM_WIN32-->  0x8007000E (= E_OUTOFMEMORY)

כדי לקרוא לכיוון השני, שולפים את ה-16 bits הנמוכים ב-PowerShell.

0x80070005 -band 0xFFFF   # 5 → ERROR_ACCESS_DENIED
0x80072EE7 -band 0xFFFF   # 12007 → ERROR_INTERNET_NAME_NOT_RESOLVED (WinINet)

כמו בדוגמה השנייה, גם שגיאות WinINet ו-WinHTTP (טווח הקודים 12000) מוגדרות במרחב קודי שגיאת Win321, ולכן 0x8007xxxx של רשת אפשר לפרק באותו הליך. המיומנות המעשית החשובה ביותר לקחת מהמאמר: ברגע שרואים 0x8007, ממירים את 4 הספרות הנמוכות ל-decimal.

יש אזהרה הפוכה ל-0x8004xxxx (FACILITY_ITF). לקוד FACILITY_ITF מי שמגדיר את המשמעות משתנה לפי interface, ולכן אותו ערך 32-bit יכול לומר משהו אחר אם מי שהחזיר אותו שונה.5 ל-0x8004xxxx לא מוכר מחפשים לא בחיפוש גנרי אלא בתיעוד הרכיב שהחזיר (ספרייה, SDK של driver, מוצר שרת).

איך מחפשים משתנה בין 0x8007 ל-0x8004FACILITY_WIN32 0x8007xxxx נקרא בפירוק מכני של ה-16 bits הנמוכים, אבל ל-FACILITY_ITF 0x8004xxxx מי שמגדיר משמעות משתנה לפי interface, לכן מחפשים בחומרים של הרכיב שהחזיר7, WIN324, ITFFacility הוא?המרת ה-16 bits הנמוכים ל-decimalהמשמעות שונה לפי מי שהחזירלקרוא כשגיאת Win32לחפש בחומרים של מי שהחזיר

איור 10: 0x8007xxxx אפשר לפרק מכנית; 0x8004xxxx מחפשים בחומרים של הרכיב שהחזיר.

5. NTSTATUS — קודי שכבת ה-kernel ועולם הקריסות

5.1. הפריסה ו-Severity

NTSTATUS הוא קוד 32-bit שה-kernel, drivers ו-native APIs של ntdll משתמשים בו, והפריסה דומה ל-HRESULT בלי להיות זהה.3

מיקום ה-bit שם משמעות
31–30 Sev Severity. 00 = success, 01 = informational, 10 = warning, 11 = error
29 C Customer bit
28 N reserved (0, כדי שאפשר יהיה למפות ל-HRESULT)
27–16 Facility Facility (12 bits)
15–0 Code קוד פירוט

כי severity הוא 2 bits, אפשר לקרוא את הסוג מהספרה הראשונה ב-hex. 0xC… הוא error (11), 0x8… הוא warning (10), 0x4… הוא informational (01), 0x0–0x3… הוא success. breakpoint exception 0x80000003 (STATUS_BREAKPOINT) היא דוגמה מייצגת ל”warning, לא error”.37

NTSTATUS נקרא לפי סוג מהספרה המובילהכי severity הוא 2 bits, NTSTATUS נקרא כ-error אם הספרה הראשונה ב-hex היא 0xC, warning אם 0x8, informational אם 0x4, ו-success אם 0x0 עד 0x30xC0x80x40x0–0x3הספרה הראשונה ב-hex?errorwarninginformationalsuccessדוגמה: 0x80000003 היא warning

איור 11: NTSTATUS נקרא לפי סוג מהספרה הראשונה ב-hex. 0x80000003 הוא “warning, לא error”.

5.2. איפה פוגשים אותו — exception codes, STOP codes ו-Event Log

המצבים שבהם אנשי IT ומפתחים פוגשים NTSTATUS קשורים בעיקר לקריסות.

  • Exception code של קריסת אפליקציה: “Exception code: 0xc0000005” שנרשם ב-Event Log תחת “Application Error (event ID 1000)” הוא NTSTATUS. ערכים מייצגים:7
ערך symbol משמעות
0xC0000005 STATUS_ACCESS_VIOLATION access violation (גישה לא חוקית לזיכרון)
0xC0000135 STATUS_DLL_NOT_FOUND DLL נדרשת לא נמצאה ואי אפשר להתחיל
0xC00000FD STATUS_STACK_OVERFLOW stack overflow
0xC0000374 STATUS_HEAP_CORRUPTION heap corruption
  • STOP code של מסך כחול: במבט ראשון הם נראים דומים, אבל STOP code (bug check code) הוא מערכת מספור משלו, נפרדת מ-NTSTATUS, כמו 0x0000009F (DRIVER_POWER_STATE_FAILURE), ויש לו reference ייעודי.14 מספיק לזכור את ההבחנה: “0xC0000005 הוא NTSTATUS; STOP 0x9F הוא bug check code ואסור לחפש אותו בטבלת NTSTATUS”.
  • עמודת Result של Process Monitor: NAME NOT FOUND ו-ACCESS DENIED בעמודת Result של Procmon הם שמות תצוגה של ה-NTSTATUS שה-kernel החזיר (STATUS_OBJECT_NAME_NOT_FOUND, STATUS_ACCESS_DENIED). כאן גם רואים בבירור את ההתאמה בין השכבות: כשל I/O של קובץ נצפה במונחי NTSTATUS, ואז מומר לשגיאת Win32 ומגיע לאפליקציה.
הבחנה בין exception code ל-STOP codeקוראים exception code של Event Log כ-NTSTATUS; מחפשים STOP code של מסך כחול ב-reference הייעודי של bug-check codes, מערכת אחרתexception codeSTOP codeאיפה הופיע הקוד?לקרוא כ-NTSTATUSלחפש בטבלת bug-check codesדוגמה: 0xC0000005דוגמה: 0x0000009F

איור 12: exception code ב-Event Log הוא NTSTATUS; STOP code של מסך כחול הוא מערכת אחרת. לא מחפשים בטבלה הלא נכונה.

חקירה מעבר ל-exception code, כלומר איסוף וניתוח של crash dump, מכוסה ב”מבוא לאיסוף crash dump ב-Windows” וב”קריאת crash dumps עם WinDbg + SOS”.

5.3. הקשר ל-HRESULT —‏ N-bit ו-RtlNtStatusToDosError

הגשר בין NTSTATUS לשתי השכבות האחרות עובר בשני נתיבים.

  1. מיפוי למרחב HRESULT: הדלקת N-bit של HRESULT (0x10000000) מכניסה ערך NTSTATUS למרחב HRESULT כמו שהוא (המאקרו HRESULT_FROM_NT ב-winerror.h). מיפוי של 0xC0000005 הופך למשל ל-0xD0000005. כשרואים HRESULT שמתחיל ב-0xD, השלב הנכון הוא להוריד את N-bit ולקרוא כ-NTSTATUS.2
  2. המרה לקוד שגיאת Win32: RtlNtStatusToDosError של ntdll ממיר NTSTATUS לקוד שגיאת Win32 המתאים. ערך בלי התאמה מוגדרת הופך ל-ERROR_MR_MID_NOT_FOUND.12 למשל STATUS_ACCESS_VIOLATION (0xC0000005) מומר ל-ERROR_NOACCESS (998), ו-STATUS_OBJECT_NAME_NOT_FOUND (0xC0000034) ל-ERROR_FILE_NOT_FOUND (2). כדאי לזכור גם שה-vocabulary העשיר של ה-kernel לפעמים מעוגל בשכבת Win32 להבחנה גסה יותר.
שני גשרים מ-NTSTATUS לשכבות האחרותNTSTATUS עובר לשכבות האחרות בשתי דרכים: מיפוי למרחב HRESULT בהדלקת N-bit, והמרה לקוד שגיאת Win32 על ידי RtlNtStatusToDosErrorהדלקת N-bitRtlNtStatusToDosErrorNTSTATUS (0xC0000005)HRESULT (0xD0000005)שגיאת Win32 998 (ERROR_NOACCESS)ERROR_MR_MID_NOT_FOUND אם אין התאמה מוגדרת

איור 13: יש שני גשרי NTSTATUS. התחלה 0xD נקראת כ-NTSTATUS אחרי שמורידים את N-bit.

6. COM ו-.NET — איך קוד שגיאה ממופה ל-exception

6.1. הגישה של COM —‏ HRESULT + IErrorInfo

מתודת COM מחזירה ביסוד HRESULT, אבל יש גבול למה שאפשר לדחוס ב-32 bit, ולכן כהשלמה מנגנון IErrorInfo יכול להעביר בנפרד מחרוזת תיאור שגיאה ומקור. ב-C++, המחלקה _com_error בתמיכת ה-compiler מטפלת ב-HRESULT וב-IErrorInfo יחד. אפליקציה שתיבת השגיאה שלה מציגה “קוד + תיאור” לרוב מעבירה את התיאור במנגנון הזה.

IErrorInfo שמשלים HRESULTיש גבול למה שאפשר לדחוס ב-HRESULT בן 32 bit, לכן מחרוזת תיאור שגיאה ומקור מועברים בנפרד ב-IErrorInfo, וב-C++ המחלקה _com_error מטפלת בשניהם יחדHRESULT (רק 32 bit)יש גבול למה שנכנסIErrorInfo נושא את התיאור_com_error מטפל בהם יחדקוד + תיאור של התיבה

איור 14: מחרוזת תיאור שלא נכנסת ל-HRESULT בן 32 bit מגיעה בנפרד דרך IErrorInfo.

6.2. הגישה של .NET — מ-HRESULT לסוג exception

כשה-.NET runtime מקבל כישלון HRESULT ב-COM interop, הוא ממיר אותו ל-exception. HRESULT מוכר ממופה לסוג ה-exception המתאים; לא מוכר הופך ל-COMException.11

מיפוי מ-HRESULT ל-exception של .NETHRESULT כישלון שמתקבל ב-COM interop מומר לסוג ה-exception המתאים אם מוכר, או ל-COMException אם לא, ובכל מקרה הערך המקורי נשמר ב-Exception.HResultכןלאHRESULT כישלוןיש mapping מוכר?המרה לסוג ה-exception המתאיםהמרה ל-COMExceptionהערך המקורי נשמר ב-Exception.HResult

איור 15: .NET ממפה HRESULT לסוג exception, והערך המקורי נשאר ב-Exception.HResult בכל exception.

HRESULT סוג exception ב-.NET
E_ACCESSDENIED (0x80070005) UnauthorizedAccessException
E_OUTOFMEMORY (0x8007000E) OutOfMemoryException
E_INVALIDARG (0x80070057) ArgumentException
E_NOTIMPL (0x80004001) NotImplementedException
ערך בלי mapping מוגדר COMException (הערך המקורי במאפיין ErrorCode)

בכל exception, ה-HRESULT המקורי נשמר במאפיין Exception.HResult. הסתעפות בטיפול ב-exceptions של file I/O כמו “לנסות שוב רק ב-sharing violation” אפשר לכתוב לפי הערך הזה.

try
{
    using var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None);
}
catch (IOException ex) when (ex.HResult == unchecked((int)0x80070020))
{
    // 0x80070020 = HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION)
    // Another process is holding the file — wait a little and retry, for example
}

6.3. P/Invoke ו-GetLastError

כשקוראים ל-Win32 API ישירות דרך P/Invoke, מגדירים SetLastError = true ב-DllImport (או LibraryImport), ואז שולפים ב-Marshal.GetLastWin32Error (מ-.NET 6, המקביל GetLastPInvokeError). להגדיר את GetLastError עצמו כ-P/Invoke ולקרוא לו אינו מדויק, כי קריאת API בתוך ה-runtime יכולה לדרוס את הערך.15

שליפת השגיאה האחרונה ב-P/Invokeלציין SetLastError כ-true ולשלוף ב-Marshal.GetLastWin32Error נכון; לקרוא ל-GetLastError ישירות ב-P/Invoke אינו מדויק בגלל overwrite של ה-runtimeקריאה ל-Win32 API דרך P/Invokeציון SetLastError=trueשליפה ב-GetLastWin32Errorהגדרה שקוראת ל-GetLastError ישירותה-runtime דורס וזה לא מדויק

איור 16: ב-P/Invoke משתמשים ב-SetLastError=true וב-Marshal.GetLastWin32Error כזוג. קריאה ישירה ל-GetLastError אינה מדויקת.

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern SafeFileHandle CreateFileW(string fileName, uint access, uint share,
    IntPtr security, uint disposition, uint flags, IntPtr template);

// Receive the return value as SafeFileHandle, not IntPtr, and close it reliably with using
// (leaving it as IntPtr leaks a kernel handle)
using var handle = CreateFileW(@"C:\ProgramData\MyApp\config.dat",
    0x80000000 /*GENERIC_READ*/, 0, IntPtr.Zero, 3 /*OPEN_EXISTING*/, 0, IntPtr.Zero);
if (handle.IsInvalid)
{
    int code = Marshal.GetLastWin32Error();              // Example: 5
    var message = new Win32Exception(code).Message;       // Example: Access is denied.
    logger.LogError("CreateFileW failed: {Code} (0x{Code:X8}) {Message}",
        code, code, message);
}

Win32Exception שולף את מחרוזת הודעת מערכת ההפעלה מקוד שגיאת Win32, ולכן אפשר להשתמש בו כמו שהוא כדי להשאיר בלוג גם את הקוד וגם את ההודעה. שאלת התכנון באיזו שכבה לעשות catch ל-exception ואיך לרשום אותה בלוג מכוסה ב”איפה לשים catch ו-logging בטיפול ב-exceptions?”.

7. כלי המרה וחקירה בפועל — cheat sheet להעתקה

7.1. err.exe (Microsoft Error Lookup Tool)

כלי חיפוש שגיאות עצמאי ש-Microsoft מפיצה. הוא עובר על הרבה header files כמו winerror.h ו-ntstatus.h ומציג הגדרות והודעות שתואמות לקוד שצוין.8

err 0x80070005
err 5
err 0xC0000005

מספר אחד יכול לפגוע בכמה headers (למשל “5” תואם הגדרות במקומות שונים מלבד Win32 ERROR_ACCESS_DENIED), ולכן איזה מהמועמדים סביר בוחרים לפי ה-context. שם קובץ ההורדה כולל גרסה (Err_6.4.5.exe בעת הכתיבה), ושימו לב גם שהגדרות הקוד מבוססות על ה-headers בזמן האריזה.8

לבחור תוצאות חיפוש err.exe לפי contexterr.exe עובר על הרבה header files ומציג הגדרות תואמות, לכן כשכמה מועמדים עולים לאותו מספר, בוחרים את הסביר לפי contextהזנת err 5מעבר על הרבה headersכמה הגדרות פגעובחירת מועמד סביר לפי context

איור 17: err.exe הוא חיפוש חוצה-headers, ולכן כמה מועמדים יכולים לעלות, ואת הסביר בוחרים לפי context.

7.2. פקודות מובנות ב-Windows

מה שאפשר להשתמש בו בלי התקנה נוספת הם certutil ו-net helpmsg. האפשרות -error של certutil מציגה את טקסט ההודעה שמתאים לקוד שגיאה, ומקבלת HRESULT ב-hex או decimal.9

certutil -error 0x80070005
certutil -error 5
net helpmsg 5

net helpmsg הוא לקוד שגיאת Win32 ב-decimal בלבד, אבל בסביבה עברית ההודעה חוזרת בעברית, ולכן אפשר להשתמש בה כמו שהיא בהסבר למשתמש.

איך לבחור בין הפקודות הסטנדרטיותקוד שגיאת Win32 עשרוני מחפשים ב-net helpmsg; קוד שכולל hex, כולל HRESULT, מחפשים באפשרות -error של certutilWin32 עשרוניכולל hexהקוד שיש לכם הוא?net helpmsgcertutil -errorהודעה עברית חוזרתמקבל hex ו-decimal

איור 18: איך לבחור בין הפקודות הסטנדרטיות. שגיאת Win32 עשרונית היא net helpmsg; אם יש hex, certutil -error.

7.3. אוסף one-liners ב-PowerShell

# Win32 error code → OS message string
[System.ComponentModel.Win32Exception]::new(5).Message
# → Access is denied.

# Negative decimal → hex notation (confirm the identity of an HRESULT)
'0x{0:X8}' -f -2147467259     # 0x80004005

# 0x8007xxxx → the Win32 error code in the low 16 bits
0x80070005 -band 0xFFFF        # 5

# HRESULT → confirm the exception .NET maps
[System.Runtime.InteropServices.Marshal]::GetExceptionForHR(-2147024891)
# → UnauthorizedAccessException (0x80070005)

# Win32 error code → HRESULT (reproduce the wrap)
'0x{0:X8}' -f (0x80070000 -bor 32)   # 0x80070020

7.4. !error של WinDbg

כדי לחפש קוד במהלך ניתוח dump, ההרחבה !error של WinDbg מהירה. כברירת מחדל היא מפרשת כקוד שגיאת Win32; מעבירים 1 כארגומנט שני והיא מפרשת כ-NTSTATUS.10

0:000> !error 5
Error code: (Win32) 0x5 (5) - Access is denied.

0:000> !error 0xc0000005 1
Error code: (NTSTATUS) 0xc0000005 - <Access violation>

ב-crash dump, !analyze -v מציג אוטומטית את ה-exception code (NTSTATUS), ולכן הזרימה היא לאשר משם את המשמעות ב-!error <code> 1.

זרימת אישור exception code ב-WinDbgב-crash dump פקודת analyze מציגה אוטומטית את ה-exception code; מעבירים את הקוד להרחבת error עם ארגומנט שני 1 ומאשרים את המשמעות כ-NTSTATUSפתיחת ה-crash dumpהרצת !analyze -vה-exception code מוצגאישור המשמעות ב-!error code 1

איור 19: בניתוח dump מחפשים את ה-exception code ש-!analyze -v הציג ב-!error עם דגל 1.

8. הליך החקירה — מזיהוי השכבה ועד התאמה מול ה-context

מרכיבים את הידע עד כאן להליך לחקירת קוד שגיאה בפועל.

  1. מיישרים את הייצוג. אם זה decimal שלילי, ממירים ל-hex בן 8 ספרות. ממלאים אפסים ל-hex קצר מ-8 ספרות וקוראים.
  2. קובעים מאיזו שכבה הקוד. כמו בטבלת הזיהוי למטה, הספרות המובילות כמעט מחליטות.
  3. מפרקים ומוציאים את הקוד האמיתי. פעולה מכנית: ה-16 bits הנמוכים אם 0x8007xxxx, הורדת N-bit אם 0xDxxxxxxx.
  4. שולפים שם והגדרה בכלי. מאשרים את שם ה-symbol ואת ההודעה ב-err.exe, certutil או !error.
  5. מתאימים מול ה-context. מזהים איזו אפליקציה, איזו פעולה, איזה API, נכשל מול מה, מלוג האפליקציה, Event Log ו-Procmon. הקוד הוא “סוג הכישלון”; ה-context הוא “איפה הסיבה”.
הליך חקירת קוד שגיאהתבנית החקירה של יישור הייצוג ל-hex, זיהוי השכבה מהספרות המובילות, פירוק והוצאת הקוד האמיתי, חיפוש שם והגדרה בכלי, ואז התאמה מול ה-contextעשרוני0x80070xC0xDיישור ל-hexספרות מובילות?קריאה כשגיאת Win32ה-16 bits הנמוכים → decimalקריאה כ-NTSTATUSהורדת N-bit וקריאהחיפוש שם/הגדרההתאמת context (Procmon)

איור 20: תבנית החקירה. מיישרים את הייצוג, מזהים שכבה ומפרקים, שולפים שם, ואז מתאימים מול ה-context.

מראה מועמד ראשון איך לפרק ולהמיר
decimal בן 1 עד 5 ספרות (5, 1223 וכדומה) קוד שגיאת Win32 כמו שהוא ל-net helpmsg או err.exe
decimal שלילי (2147024891- וכדומה) HRESULT המרה ל-hex בן 8 ספרות, ואז זיהוי לפי השורות למטה
0x8007xxxx HRESULT (FACILITY_WIN32) המרת ה-16 bits הנמוכים ל-decimal וקריאה כ-Win32
0x8004xxxx HRESULT (FACILITY_ITF) חיפוש בתיעוד הרכיב שהחזיר
0x8000xxxx HRESULT (FACILITY_NULL) קוד גנרי כמו E_FAIL. מעבירים את המשקל לחקירת context
0xCxxxxxxx NTSTATUS (error) !error <code> 1; המרה ל-Win32 וקריאה אם צריך
0xDxxxxxxx מיפוי HRESULT של NTSTATUS הורדת N-bit (0x10000000) וקריאה כ-NTSTATUS
Facility משלו כמו 0x8024xxxx HRESULT ייחודי לתחום מזהים את התחום מערך Facility ועוברים לחומרים ייעודיים (0x8024… הוא Windows Update)2

מה שעוזר במיוחד בצעד 5 “התאמה מול ה-context” הוא עמודת Result של Process Monitor. גם אם האפליקציה מציגה רק “0x80070002”, Procmon אומר בשורה אחת “איזה process, מול איזה path, קיבל NAME NOT FOUND”. לחיפוש מצד Event Log ראו גם “מבוא ל-Event Log של Windows ול-ETW”.

9. קריאות שגויות נפוצות — תבניות שמאריכות את החקירה

לבסוף, תבניות קריאה שגויה שמופיעות בייעוץ אמיתי.

קריאה שגויה 1: לחשוב ש-0x80004005 הוא “קוד שמצביע על סיבה ספציפית”

E_FAIL הוא “Unspecified failure”, ואותו ערך מופיע ב-Windows Update, ברשת ובמסדי נתונים. לנסות כל תיקון שעולה כשמחפשים את הקוד הזה הוא כמעט בוודאות הדרך הארוכה. מצמצמים לא מהקוד אלא מ”איזו אפליקציה, איזו פעולה, לוגים אחרים באותו זמן”.6

קריאה שגויה 2: לא להבחין ש-decimal שלילי הוא HRESULT

מקרה של חיפוש לוג שאומר “Error -2147467259 occurred” כמו שהוא, או בלבול מ”שגיאה עם מינוס?”. כשרואים שלילי, ממירים ל-hex. זה לבד אומר שזה 0x80004005 (E_FAIL), ומתחבר לידע של קריאה שגויה 1.

קריאה שגויה 3: לחפש את כל 8 הספרות של 0x8007xxxx ולא להסתכל על שגיאת Win32 שמתחת

המהות של 0x80070005 היא “5 = הגישה נדחתה”. אחרי ששולפים את ה-16 bits הנמוכים, לחשוב “מה שגיאת Win32 5 אומרת ב-context של הפעולה הזו” מגיע לליבה מהר יותר מחיפוש כל 8 הספרות.

קריאה שגויה 4: להניח “אותו קוד = אותה סיבה”

אם פעם “שגיאה 5 נגרמה מאנטי-וירוס”, נוטים לקפוץ לאותו תיקון בשגיאה 5 הבאה. גם באותו קוד, אם ה-API שנכשל ו-resource היעד שונים, הסיבה היא דבר אחר. אישור משמעות הקוד וזיהוי היעד ב-Procmon או דומה הם זוג, בכל פעם.

קריאה שגויה 5: לבלבל שגיאת Win32 5 עם 0xC0000005, ו-STOP code עם NTSTATUS

להתייחס ל-ERROR_ACCESS_DENIED ול-STATUS_ACCESS_VIOLATION כאותו דבר בגלל הקשר “5” שולח את החקירה לכיוונים שונים לגמרי — בעיית הרשאות מול באג בתוכנית. גם STOP code של מסך כחול הוא מערכת אחרת מ-NTSTATUS, ולכן חיפוש 0x9F בטבלת NTSTATUS לא נותן תשובה משמעותית.14

לשגיאה 5 ול-0xC0000005 יש כיווני חקירה שוניםשגיאת Win32 5 חוקרים כבעיית הרשאות, ו-NTSTATUS 0xC0000005 כבאג בתוכנית; להתייחס אליהם כאותו דבר שולח את החקירה לכיוון אחרשגיאת Win32 5חקירת בעיית הרשאותNTSTATUS 0xC0000005חקירת באג בתוכניתקודים לא קשורים ממערכות שונות

איור 21: לא מתייחסים אליהם כאותו דבר בגלל הקשר “5”. שגיאה 5 הולכת לבעיית הרשאות; 0xC0000005 לבאג בתוכנית.

10. סיכום

  • קודי שגיאה ב-Windows הם מבנה שלוש שכבות של קודי שגיאת Win32, HRESULT ו-NTSTATUS. קודם קובעים איזו שכבה, מי החזיר את הקוד.
  • תנודות הייצוג (decimal / hex / שלילי) אפשר ליישר מכנית. ממירים שלילי ל-hex בן 8 ספרות ואז קוראים.
  • HRESULT הוא מבנה bits של S/R/C/N/X + Facility (11 bits) + Code (16 bits), ו-0x8007xxxx הוא ה-pattern החשוב ביותר: שגיאת Win32 עטופה. ממירים את ה-16 bits הנמוכים ל-decimal ומוציאים את הקוד האמיתי.
  • קוד גנרי כמו 0x80004005 (E_FAIL) אינו מציין סיבה. ההחלטה להפסיק לחפור בקוד ולעבור לחקירת context אפשרית דווקא כי מכירים את המבנה.
  • פוגשים NTSTATUS כ-exception code של קריסה או בעמודת Result של Procmon. 0xC0000005 הוא access violation, לא קשור לשגיאת Win32 5. STOP code הוא עוד מערכת.
  • ב-.NET, HRESULT ממופה לסוג exception, והערך המקורי נשאר ב-Exception.HResult. ב-P/Invoke משתמשים ב-SetLastError=true וב-Marshal.GetLastWin32Error כזוג.
  • כלי החיפוש הם certutil -error ו-net helpmsg (סטנדרט), err.exe (מכונת פיתוח), one-liners ב-PowerShell, ו-!error של WinDbg.
  • ההליך הוא “יישור הייצוג → זיהוי השכבה → פירוק → חיפוש שם → התאמה מול ה-context”. מה שהקוד אומר הוא סוג הכישלון; איפה הסיבה אומר ה-context.

בפעם הבאה שפוגשים קוד שגיאה לא מוכר, מסתכלים על הספרות המובילות לפני שמדביקים בתיבת החיפוש. 4 הספרות הנמוכות אם 0x8007, NTSTATUS אם 0xC, המרה ל-hex אם שלילי — הפירוק של 10 השניות הזה קובע במידה רבה את זמן החקירה שאחרי.

מאמרים קשורים

תחומי ייעוץ קשורים

KomuraSoft LLC מטפלת בחקירת תקלות שמתחילה מקוד שגיאה — “לא ברור מה הקוד הזה אומר”, “0x80070005 מופיע רק בסביבה מסוימת” — בתכנון error handling לאפליקציות שמערבבות Win32 API, COM ו-.NET, ובאיתור סיבות עם crash dump ו-Process Monitor. ייעוץ מצילום מסך אחד של תיבת שגיאה מתאים.

מקורות

  1. Microsoft Learn, Debug system error codes. מפתח לרשימת קודי שגיאת מערכת Win32 (0–15999); קבלת ההודעה לקוד ש-GetLastError מחזיר ב-FormatMessage ובדגל FORMAT_MESSAGE_FROM_SYSTEM; ששגיאות WinINet/WinHTTP (טווח הקודים 12000) מוגדרות במרחב הזה; ושיטות חקירה עם Microsoft Error Lookup Tool ופקודת !err. ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  2. Microsoft Open Specifications, [MS-ERREF]: HRESULT. פריסת ה-bits של HRESULT (ה-bits S, R, C, N ו-X, Facility בן 11 bits, Code בן 16 bits); ש-N-bit מציין ערך NTSTATUS שממופה למרחב HRESULT; ורשימת קודי facility כולל FACILITY_WINDOWS_UPDATE (36). ↩ ↩2 ↩3 ↩4 ↩5

  3. Microsoft Open Specifications, [MS-ERREF]: NTSTATUS. פריסת ה-bits של NTSTATUS (Sev בן 2 bits, C-bit, N-bit, Facility בן 12 bits, Code בן 16 bits); וש-severity מתפצל לארבעה סוגים: success (00), informational (01), warning (10) ו-error (11). ↩ ↩2 ↩3

  4. Microsoft Learn, HRESULT_FROM_WIN32 macro. הגדרת מאקרו winerror.h שממפה קוד שגיאת מערכת Win32 לערך HRESULT. ↩ ↩2 ↩3

  5. Microsoft Learn, Structure of COM Error Codes. תפקיד ה-severity bit של HRESULT ושדה ה-facility; ערכי FACILITY_NULL, FACILITY_RPC, FACILITY_ITF, FACILITY_WIN32 ו-FACILITY_WINDOWS; ושקוד FACILITY_ITF משמעותו מוגדרת לפי interface ואותו ערך יכול לומר משהו אחר. ↩ ↩2 ↩3

  6. Microsoft Learn, Common HRESULT values. ש-E_FAIL (0x80004005) הוא “Unspecified failure”; והגדרות ערכי HRESULT נפוצות כמו E_ACCESSDENIED (0x80070005), E_INVALIDARG (0x80070057) ו-E_OUTOFMEMORY (0x8007000E). ↩ ↩2 ↩3 ↩4

  7. Microsoft Open Specifications, [MS-ERREF]: NTSTATUS values. רשימת ערכי NTSTATUS כולל STATUS_ACCESS_VIOLATION (0xC0000005), STATUS_DLL_NOT_FOUND (0xC0000135), STATUS_STACK_OVERFLOW (0xC00000FD), STATUS_HEAP_CORRUPTION (0xC0000374) ו-STATUS_BREAKPOINT (0x80000003). ↩ ↩2 ↩3

  8. Microsoft Learn, The Microsoft Error Lookup Tool. שזה כלי עצמאי שמציג את טקסט ההודעה הקשור לקוד מצב hex על פני header files שונים כמו Winerror.h; ששם קובץ ההורדה הוא Err_6.4.5.exe; ושצריך לשים לב שההגדרות הארוזות הן נכון לזמן הקימפול. ↩ ↩2 ↩3

  9. Microsoft Learn, certutil. שאפשרות -error של certutil מציגה את טקסט ההודעה הקשור לקוד שגיאה, ושסימון שגיאה שכולל שם symbol משמש בצורה כמו 0x80070002 (WIN32: 2 ERROR_FILE_NOT_FOUND). ↩ ↩2

  10. Microsoft Learn, !error. שהרחבת !error של WinDbg מפענחת ומציגה ערכי שגיאה של Win32, Winsock, NTSTATUS ו-NetAPI; ושקביעת 1 כדגל מפרשת כ-NTSTATUS. ↩ ↩2

  11. Microsoft Learn, How to: Map HRESULTs and exceptions. מנגנון המיפוי ההדדי בין HRESULT של COM ל-exceptions של .NET; טבלת ההתאמה כמו E_NOTIMPL → NotImplementedException; ש-HRESULT בלי mapping מפורש מומר ל-COMException; וש-Message, Source וכדומה של ה-exception מאותחלים ממידע IErrorInfo. ↩ ↩2

  12. Microsoft Learn, RtlNtStatusToDosError function (winternl.h). שזו פונקציה שממירה קוד NTSTATUS לקוד שגיאת מערכת Win32 המתאים; ש-ERROR_MR_MID_NOT_FOUND מוחזר כשאין התאמה מוגדרת; ושפונקציה שמבצעת המרה הפוכה אינה קיימת. ↩ ↩2

  13. Microsoft Learn, Last-Error Code. שה-last-error code מוחזק per-thread; שיש לשלוף אותו ב-GetLastError מיד אחרי כישלון; ש-APIs שדורסים את הקוד ב-0 בהצלחה ו-APIs שלא נוגעים מעורבים; וש-bit 29 שמור לקודים שמוגדרים בידי האפליקציה. ↩ ↩2

  14. Microsoft Learn, Bug check code reference. רשימת bug check codes (STOP codes) שמוצגים במסך כחול, ואיך להציג מידע על קוד בהרחבת !analyze של WinDbg. שזו מערכת מספור משלה, נפרדת מ-NTSTATUS, אפשר לאשר מהרשימה. ↩ ↩2

  15. Microsoft Learn, Marshal.GetLastWin32Error Method. שזו דרך לשלוף את ה-last-error code של קריאת P/Invoke שהציבה את דגל SetLastError; שקריאה ישירה ל-GetLastError ב-P/Invoke אינה אמינה בגלל overwrite בקריאת API בתוך ה-runtime; ושמ-.NET 6 מומלץ GetLastPInvokeError. ↩

מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.

העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.

המאמר קשור ישירות לשירותים הבאים.

שאלות נפוצות

שאלות נפוצות בפניות בנושא המאמר.

מה המשמעות של השגיאה 0x80004005?
0x80004005 הוא HRESULT בשם E_FAIL, והמשמעות היא "Unspecified failure" (כישלון לא מוגדר). הוא אומר רק שקרה כישלון שאי אפשר לדווח עליו בפירוט; זה לא קוד שמתאר את הסיבה עצמה. לכן אותו 0x80004005 מופיע במקומות שלא קשורים זה לזה — רשת, Windows Update, VBA, database driver. כשרואים את הקוד הזה, לא חופרים במשמעות שלו. מצמצמים את הסיבה לפי ה-context: איזו אפליקציה, איזו פעולה, ואיזה מידע שגיאה נוסף יש ב-Event Log או בלוג המפורט.
מהו קוד שגיאה שלילי כמו 2147467259-?
זה HRESULT של 32 bit שמוצג כ-decimal עם סימן. ב-HRESULT, כשיש כישלון, ה-most significant bit דלוק, ולכן כ-signed integer הערך תמיד שלילי. ב-PowerShell, '0x{0:X8}' -f -2147467259 ממיר אותו חזרה ל-hex (בדוגמה הזו 0x80004005 = E_FAIL). כשרואים בלוג או בהודעת שגיאה של סקריפט מספר שלילי שמתחיל ב-214…-, הצעד הראשון הוא להמיר ל-hex ואז לחפש.
מה הדרך הכי פשוטה לבדוק מה קוד שגיאה אומר?
בלי התקנה נוספת אפשר להשתמש ב-net helpmsg 5 בשורת הפקודה (לשגיאת Win32 ב-decimal) וב-certutil -error 0x80070005. certutil מקבל גם HRESULT ב-hex ומציג את שם ה-symbol ואת טקסט ההודעה. ב-PowerShell, [System.ComponentModel.Win32Exception]::new(5).Message מחזיר את ההודעה המקומית. על מכונת פיתוח כדאי לשים את כלי החיפוש הרשמי של Microsoft, err.exe (Microsoft Error Lookup Tool); הוא מחפש ב-Win32, HRESULT ו-NTSTATUS ומציג את כל ההגדרות שתואמות בבת אחת.
איזה סוג שגיאה הוא 0xC0000005?
זה NTSTATUS בשם STATUS_ACCESS_VIOLATION, כלומר access violation (גישה לא חוקית לזיכרון). זה הקוד שרואים הכי הרבה כ-Exception code ב-Event Log או ב-crash dump כשאפליקציה קורסת, והוא מצביע על באג בתוכנית כמו dereference של pointer לא תקין או גישה לזיכרון שכבר שוחרר. השם דומה לשגיאת Win32 5 (ERROR_ACCESS_DENIED = הגישה נדחתה), אבל זה קוד לא קשור ממערכת אחרת; לא מבלבלים ביניהם. הדרך האמינה לאתר את הסיבה היא לאסוף crash dump ולנתח אותו ב-WinDbg.
למה הסיבה משתנה בכל פעם, גם כשזה אותו קוד שגיאה?
כי קוד שגיאה מתאר רק איזה סוג כישלון זה, ומה נכשל ולמה נקבע לפי ה-context של הקריאה. שגיאה 5 (הגישה נדחתה), למשל, היא אותו קוד לסיבות שונות לגמרי — הרשאות NTFS חסרות, אין הרשאות Administrator, חסימה של אנטי-וירוס וכן הלאה. במצב דומה, אם process אחר עדיין מחזיק את הקובץ פתוח, מקבלים קוד אחר (שגיאה 32 = sharing violation), וקריאה נכונה של הקוד משנה לאן בודקים. גם שגיאה 2 (הקובץ לא נמצא) לעיתים קרובות אינה הקובץ הראשי אלא DLL תלויה או קובץ הגדרות. אחרי שבודקים מה הקוד אומר, הדרך הקצרה לסיבה היא לאשר ב-Process Monitor או כלי דומה איזה API נכשל מול איזה resource.

פרופיל הכותב

עמוד היכרות עם כותב המאמר.

Go Komura

מנהל KomuraSoft LLC

מתמחה בפיתוח תוכנה עבור Windows, ייעוץ טכני וחקירת תקלות, בעיקר בפרויקטים עם מערכות קיימות ובאגים שקשה לשחזר.

קישורים ציבוריים

חזרה לבלוג