قراءة رموز أخطاء ويندوز — البنية ذات الطبقات الثلاث لـ Win32 وHRESULT وNTSTATUS
· Go Komura · Windows, رموز الأخطاء, HRESULT, NTSTATUS, Win32 API, استكشاف الأعطال, التنقيح, تطوير ويندوز
«ظهرت على شاشة التطبيق الخطأ 0x80004005. ماذا يعني؟» — في استشارات التحقيق في الحوادث هذا النوع من الأسئلة كلاسيكي. من لصق الرقم من مربع حوار خطأ مباشرة في محرّك بحث وواجه سيلاً من مقالات لا صلة بينها — فشل Windows Update، مجلد مشترك لا يتصل، خطأ وقت تشغيل VBA، فشل اتصال بقاعدة بيانات — وازداد حيرة، له رفقة كثيرة.
يحدث ذلك لأن 0x80004005 (E_FAIL) رمز عام معناه الوحيد «فشل غير محدّد». يُستخدم الرمز نفسه في مواقف لا تُحصى، لذا البحث بالرمز وحده لا يصل إلى السبب. في المقابل، رمزاً مثل 0x80070005 يمكن، إن عرفت البنية، تفكيكه في ثوانٍ قبل البحث إلى «رقم خطأ Win32 5 = رُفض الوصول، ملفوف كـ HRESULT».
رموز أخطاء ويندوز تكوّن، لأسباب تاريخية، ثلاث طبقات — رموز خطأ Win32 وHRESULT وNTSTATUS — وتُحوَّل عبر الطبقات. متى صارت هذه البنية في ذهنك، تستطيع أن تحكم بنفسك «أي طبقة وأي طرف أعاد هذا الرمز» و«ما الرمز الجوهري»، وتصبح الحركة الأولى للتحقيق أسرع بكثير.
موجّه إلى موظفي تقنية المعلومات في الشركات الصغيرة والمتوسطة ومطوّري تطبيقات ويندوز، يرتّب هذا المقال كيف تميّز أنظمة الرموز الثلاثة وتفكّكها، والعلاقة باستثناءات .NET، والبحث العملي بـ err.exe وPowerShell — استناداً إلى Microsoft Learn والمواصفة المنشورة [MS-ERREF] حتى أغسطس 2026.
1. الخلاصة أولاً
- رموز أخطاء ويندوز ثلاثة أنظمة أساساً. رموز خطأ Win32 (العشري الصغير الذي يعيده
GetLastError)، HRESULT (الرمز ذو 32 بت منذ COM، سداسي يبدأ بـ 0x8 أو عشري سالب)، وNTSTATUS (رموز طبقة النواة؛ الأخطاء تبدأ بـ 0xC).123 - العشري والسداسي كتابتان مختلفتان للرمز نفسه. «خطأ 5» و«0x5» و«الـ 16 بت الدنيا من 0x80070005» تشير كلها إلى ERROR_ACCESS_DENIED (رُفض الوصول).1
- 0x8007xxxx هو «خطأ Win32 ملفوف». رمز خطأ Win32 مخزَّن في HRESULT FACILITY_WIN32 (7)؛ حوّل الـ 16 بت الدنيا إلى عشري فتحصل على الرمز الجوهري. هذا أهم نمط في قراءة رموز الأخطاء.45
- 0x80004005 (E_FAIL) ليس رمز سبب. يعني «Unspecified failure» ولا يحمل مزيداً من المعلومات. بدلاً من الحفر في هذا الرمز، ابحث عن سياق المصدر والسجلات المرافقة.6
- العشري السالب (-2147467259 وما شابه) هو HRESULT. البت الأعلى من الـ 32 بت (بت الفشل) مضبوط، لذا العرض الموقّع سالب. حوّله إلى سداسي ثم اقرأه.2
- قيمة من 8 أرقام تبدأ بـ 0xC هي NTSTATUS. 0xC0000005 (انتهاك وصول) و0xC0000135 (DLL غير موجودة) تظهران باستمرار في سجلّ الأحداث وملفات التفريغ عند التعطّل. لا صلة لهما برقم خطأ Win32 5.7
- الرمز نفسه يتغيّر معناه بالسياق. سبب الخطأ 5 يمتد من ACL إلى الرفع ومضاد الفيروسات وملف محتجز وغير ذلك، و«الملف غير موجود» للخطأ 2 غالباً DLL تابعة. اقرأ دائماً معنى الرمز مع أي واجهة فشلت ضد ماذا.1
- أدوات التحويل والبحث قياسية.
certutil -errorوnet helpmsgمدمجتان في ويندوز؛Win32Exceptionفي PowerShell يجلب الرسالة؛ على آلة تطوير err.exe (Microsoft Error Lookup Tool)؛ في تحليل التفريغ!errorفي WinDbg.8910 - في .NET يُربط HRESULT بنوع استثناء. HRESULT معروف يذهب إلى النوع المقابل (E_ACCESSDENIED → UnauthorizedAccessException وما شابه)؛ المجهول يصبح COMException؛ القيمة الأصلية تبقى في
Exception.HResult.11
بجملة واحدة، نمط تحقيق رمز خطأ ويندوز هو «محاذاة الكتابة إلى السداسي → الحكم أي طبقة الرمز → التفكيك واستخراج الرمز الجوهري → قراءته مع السياق».
2. في ويندوز ثلاثة أنظمة لرموز الأخطاء
أولاً الخريطة العامة. تنقسم رموز أخطاء ويندوز أساساً إلى الأنظمة الثلاثة التالية، حسب الطبقة التي تعيدها.
| النظام | الطرف الرئيسي الذي يعيده | المظهر النموذجي | مثال تمثيلي |
|---|---|---|---|
| رمز خطأ Win32 | واجهة Win32 (GetLastError)، رمز خروج أمر |
عشري صغير (0–15999) | 5 = ERROR_ACCESS_DENIED |
| HRESULT | مكوّن COM، القشرة، مثبّت، أُطر كثيرة | سداسي من 8 أرقام يبدأ بـ 0x8، أو عشري سالب | 0x80004005 = E_FAIL |
| NTSTATUS | النواة، برنامج تشغيل، واجهة أصلية (ntdll) | الأخطاء سداسي من 8 أرقام يبدأ بـ 0xC | 0xC0000005 = STATUS_ACCESS_VIOLATION |
تاريخياً تراكمت بهذا الترتيب: رموز خطأ Win32 التي ورثت أرقام MS-DOS، وNTSTATUS الذي تستخدمه نواة NT داخلياً، وHRESULT المصمَّم عند إدخال COM لـ«حزم النجاح/الفشل والأصل في 32 بت». في ويندوز الحالي تدفّق التحويل يومي: النواة تعيد NTSTATUS، ونظام Win32 الفرعي يحوّله إلى رمز خطأ Win32، وطبقة COM تلفّه أبعد كـ HRESULT.124
flowchart TB
accTitle: تدفّق التحويل عبر الأنظمة الثلاثة
accDescr: يحوّل نظام Win32 الفرعي NTSTATUS الذي أعادته النواة إلى رمز خطأ Win32، وتلفّه طبقة COM أبعد كـ HRESULT
kernel["النواة وبرامج التشغيل"] --> nt["NTSTATUS(الأخطاء 0xC…)"]
nt -->|نظام Win32 الفرعي يحوّل| win["رمز خطأ Win32(5 وما شابه)"]
win -->|طبقة COM تلفّ| hr["HRESULT(0x8007xxxx)"]
الشكل 1: تدفّق التحويل عبر الطبقات. يصبح NTSTATUS النواة خطأ Win32، ثم يُلفّ أبعد كـ HRESULT.
2.1. اعتد قراءة العشري والسداسي بالتبادل
قبل تمييز الأنظمة الثلاثة تحتاج إلى امتصاص تذبذب الكتابة. الرمز نفسه يُعرض عشرياً أو سداسياً حسب الموقف.
- «خطأ 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
عندما ترى عشرياً سالباً يبدأ بـ «-214…»، حوّله انعكاساً إلى سداسي. ذلك وحده يقطع كثيراً من الضياع عند مدخل التحقيق.
flowchart TB
accTitle: ثلاثة مظاهر للرمز نفسه
accDescr: الخطأ العشري 5 والسداسي 0x5 والـ 16 بت الدنيا من 0x80070005 تشير كلها إلى ERROR_ACCESS_DENIED نفسه
d["كتابة عشرية: خطأ 5"] --> same["ERROR_ACCESS_DENIED"]
h["كتابة سداسية: 0x5"] --> same
l["الـ 16 بت الدنيا من 0x80070005"] --> same
same -.-> memo["كتابة مختلفة، الرمز نفسه"]
الشكل 2: العشري والسداسي والـ 16 بت الدنيا من HRESULT كتابات مختلفة فقط للرمز نفسه.
3. رموز خطأ Win32 — GetLastError وFORMAT_MESSAGE
3.1. سلوك GetLastError الأساسي
كثير من واجهات Win32 مثل CreateFile وRegOpenKeyEx تشير إلى الفشل بالقيمة المعادة (FALSE وNULL وINVALID_HANDLE_VALUE وما شابه) وتخزّن رمز الخطأ التفصيلي في «last-error code» يُحفظ لكل خيط. يسترجعه المستدعي بـ GetLastError فوراً بعد تأكيد الفشل.13
تحفظان عمليتان.13
- اقرأ فوراً بعد الفشل. إن أدرجت استدعاء واجهة آخر (دالة تسجيل مثلاً) بينها، قد يكتب ذلك الاستدعاء فوق last-error code.
- لا تعتمد على القيمة عند النجاح. بعض الواجهات تصفّر last-error code عند النجاح؛ وبعضها لا يمسّه. القاعدة تأكيد الفشل من القيمة المعادة ثم القراءة.
sequenceDiagram
accTitle: اقرأ GetLastError فوراً بعد الفشل
accDescr: بعد تأكيد الفشل من القيمة المعادة استرجع last-error code بـ GetLastError فوراً دون إدراج استدعاء واجهة آخر
participant app as App
participant api as Win32 API
app->>api: استدعاء CreateFile
api-->>app: قيمة إعادة فشل
app->>api: GetLastError
api-->>app: الرمز 5
Note over app: إدراج واجهة أخرى بينها قد يكتب فوقه
الشكل 3: اقرأ last-error code فوراً بعد الفشل. إدراج استدعاء واجهة آخر بينها قد يكتب فوقه.
للحصول على سلسلة رسالة من رمز استخدم 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);
}
ترك العشري والسداسي ونص الرسالة معاً في سجلّ تطبيقك، كهذا، يجعل تحقيقاً لاحقاً أسرع بخطوة.
flowchart TB
accTitle: ابحث عن رسالة من رمز واتركها في السجلّ
accDescr: مرّر العلم FORMAT_MESSAGE_FROM_SYSTEM إلى FormatMessage للحصول على سلسلة رسالة رمز الخطأ، واترك العشري والسداسي والنص في السجلّ
code["رمز خطأ(مثال: 5)"] --> fm["الحصول على السلسلة بـ FormatMessage"]
fm --> msg["نص الرسالة"]
msg --> log["التسجيل في السجلّ"]
log -.-> both["اكتب العشري والسداسي والنص معاً"]
الشكل 4: حوّل رمز الخطأ إلى سلسلة رسالة بـ FormatMessage، واترك العشري والسداسي والنص معاً في السجلّ.
3.2. رموز تمثيلية تظهر باستمرار في الميدان
رموز خطأ Win32 معرّفة في النطاق 0–15999، ولدى Microsoft Learn قائمة كاملة.1 من بينها الوجوه التي تلقاها مراراً في تحقيق الحوادث التالية.
| عشري | سداسي | الرمز | المعنى |
|---|---|---|---|
| 2 | 0x2 | ERROR_FILE_NOT_FOUND | الملف المحدّد غير موجود |
| 3 | 0x3 | ERROR_PATH_NOT_FOUND | المسار المحدّد غير موجود |
| 5 | 0x5 | ERROR_ACCESS_DENIED | رُفض الوصول |
| 32 | 0x20 | ERROR_SHARING_VIOLATION | عملية أخرى تستخدمه والوصول غير ممكن |
| 87 | 0x57 | ERROR_INVALID_PARAMETER | المعامل غير صحيح |
| 122 | 0x7A | ERROR_INSUFFICIENT_BUFFER | المخزن المؤقت الممرَّر صغير جداً |
| 998 | 0x3E6 | ERROR_NOACCESS | وصول غير صالح إلى موقع ذاكرة |
| 1223 | 0x4C1 | ERROR_CANCELLED | ألغى المستخدم العملية |
من هذه، 998 (ERROR_NOACCESS) ليس «رُفض الوصول» بل تعبير Win32 عن انتهاك وصول إلى الذاكرة، شكل NTSTATUS STATUS_ACCESS_VIOLATION المذكور لاحقاً بعد التحويل إلى طبقة Win32. احذر الخلط مع الرقم 5. أيضاً 1223 (ERROR_CANCELLED) رمز يظهر عندما يختار المستخدم «لا» في مربع رفع UAC مثلاً — أقرب إلى «أُلغي» منه إلى خطأ.
flowchart TB
accTitle: الخطأ 998 و5 شيئان مختلفان
accDescr: 998 انتهاك وصول إلى الذاكرة، انتهاك وصول NTSTATUS محوَّل إلى طبقة Win32، ويختلف عن 5 الذي يمثّل رفض الوصول
nt["NTSTATUS 0xC0000005"] -->|حُوِّل إلى طبقة Win32| e998["خطأ 998(ERROR_NOACCESS)"]
e998 -.-> m1["المعنى انتهاك وصول إلى الذاكرة"]
e5["خطأ 5(رُفض الوصول)"] -.-> m2["مشكلة صلاحيات. شيء مختلف عن 998"]
الشكل 5: الخطأ 998 انتهاك وصول NTSTATUS محوَّل إلى طبقة Win32، شيء مختلف عن رفض الوصول 5.
3.3. الرمز نفسه يتغيّر معناه بالسياق
أهم من حفظ جدول الرموز التمثيلية الإحساس بأن رمز الخطأ يخبرك فقط «نوع الفشل».
- الخطأ 5 (رُفض الوصول): مرشّحو السبب يتّسعون — ACL NTFS غير كافٍ، الكتابة في منطقة محمية بلا امتيازات مسؤول، حظر مضاد فيروسات أو AppLocker، امتيازات حساب خدمة غير كافية، وهكذا.
- الخطأ 2 (الملف غير موجود): ليس بالضرورة الملف الذي حدّده المستخدم. DLL تابعة حاول الـ EXE تحميلها ضمناً، ملف إعدادات رُئي في موضع خاطئ بسبب إعادة توجيه السجلّ (32 بت/64 بت)، مسار فشل توسيع متغيّر بيئته — «أي ملف» غير موجود لا يظهر من الرمز.
- الخطأ 32 (انتهاك مشاركة): «أي عملية تحتفظ به» هو السؤال الحقيقي، لكن الرمز لا يخبرك بذلك.
flowchart TB
accTitle: سبب الخطأ 5 يقرّره السياق
accDescr: حتى رفض الوصول نفسه له عدة مرشّحي سبب مثل ACL غير كافٍ أو غياب امتيازات المسؤول، وتحتاج إلى تحديد أي واجهة فشلت ضد ماذا
e5["خطأ 5(رُفض الوصول)"] --> c1["ACL غير كافٍ"]
e5 --> c2["بلا صلاحيات المسؤول"]
e5 --> c3["حظر منتج أمني"]
e5 --> c4["امتيازات الخدمة منخفضة"]
c1 --> next["Procmon: هدف الفشل"]
c2 --> next
c3 --> next
c4 --> next
الشكل 6: الرمز يخبرك فقط «نوع الفشل». للخطأ 5 عدة مرشّحي سبب، وتحديد الهدف مطلوب.
الأداة التي تقيس «أي واجهة، ضد أي اسم كائن، أعادت أي نتيجة» هي Process Monitor. استخدامها مفصّل في «دليل عملي لأداة Process Monitor (ProcMon)». البحث عن معنى رمز الخطأ وتحديد الهدف الذي فشل عجلتان للعربة نفسها.
4. HRESULT — قراءة البنية المحزومة في 32 بت
4.1. تخطيط البتات
HRESULT تنسيق يحزم النجاح/الفشل والأصل ورمز تفصيل في قيمة واحدة ذات 32 بت. تعرّفه المواصفة المنشورة [MS-ERREF] بالتخطيط التالي.2
| موضع البت | الاسم | المعنى |
|---|---|---|
| 31 | S | الخطورة. 0 = نجاح، 1 = فشل |
| 30 | R | محجوز (جزء من الخطورة عند ربط NTSTATUS) |
| 29 | C | بت العميل. 1 يعني رمزاً عرّفه غير Microsoft |
| 28 | N | 1 يعني قيمة NTSTATUS مربوطة في فضاء HRESULT |
| 27 | X | محجوز (0) |
| 26–16 | Facility | رمز مرفق يشير إلى الأصل (11 بت) |
| 15–0 | Code | رمز تفصيل داخل المرفق (16 بت) |
بت S الأعلى 1، أي أن HRESULT الذي تبدأ كتابته السداسية من 0x8 فما فوق هو فشل. عرضه كعدد صحيح موقّع ذي 32 بت يجعله سالباً — تلك هوية «-214…» المذكورة سابقاً.
flowchart TB
accTitle: علاقة بت S والعرض السالب
accDescr: HRESULT الفشل يضبط بت S الأعلى إلى 1، لذا في السداسي يبدأ من 0x8 فما فوق، وكعدد صحيح موقّع ذي 32 بت يكون سالباً
s["بت S = 1(فشل)"] --> hex["السداسي يبدأ من 0x8 فما فوق"]
hex --> neg["العرض الموقّع سالب"]
neg --> back["عند سالب حوّل إلى سداسي واقرأ"]
الشكل 7: HRESULT الفشل يبدأ من 0x8 فما فوق لأن بت S هو 1، والعرض الموقّع سالب.
قيم Facility التمثيلية كالتالي.5
| Facility | القيمة | المظهر السداسي | المعنى |
|---|---|---|---|
| FACILITY_NULL | 0 | 0x8000xxxx | رموز شائعة واسعة (E_FAIL وE_UNEXPECTED وما شابه) |
| FACILITY_RPC | 1 | 0x8001xxxx | أصل RPC |
| FACILITY_ITF | 4 | 0x8004xxxx | خطأ معرَّف بالواجهة (المعنى يعتمد على الواجهة) |
| FACILITY_WIN32 | 7 | 0x8007xxxx | رمز خطأ Win32 ملفوف |
| FACILITY_WINDOWS | 8 | 0x8008xxxx | واجهات إضافية عرّفتها 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، توقف عن الحفر في الرمز نفسه هناك، وانقل وزن التحقيق إلى «أي مكوّن أعاده» و«هل هناك تفصيل في سجلّ الأحداث أو سجلّ التطبيق في الوقت نفسه».
لـ 0x80070005: S=1، Facility=7 (FACILITY_WIN32)، Code=0x0005=5. ترى أنه رقم خطأ Win32 5 (ERROR_ACCESS_DENIED) ملفوف كـ HRESULT. الاسم المستعار E_ACCESSDENIED هو في الجوهر هذه القيمة.6
حتى لـ«رُفض الوصول» نفسه، 0x80070005 لفّ فشل ملموس وقع في طبقة Win32، وكمية المعلومات مختلفة تماماً عن 0x80004005.
flowchart TB
accTitle: تفكيك 0x80004005 و0x80070005
accDescr: 0x80004005 رمز FACILITY_NULL العام E_FAIL بلا تفصيل ويجب الانتقال إلى تحقيق سياق؛ 0x80070005 هو FACILITY_WIN32 ويُقرأ كلفّ رقم خطأ Win32 5، رُفض الوصول
a["0x80004005"] --> af["Facility=0(FACILITY_NULL)"]
af --> ac["Code=0x4005 → E_FAIL"]
ac --> ax["فشل غير محدّد. إلى تحقيق السياق"]
b["0x80070005"] --> bf["Facility=7(FACILITY_WIN32)"]
bf --> bc["Code=0x0005 → 5"]
bc --> bx["ERROR_ACCESS_DENIED"]
الشكل 8: حتى «الفشل» نفسه تختلف كمية معلوماته بعد التفكيك. يمكن السير بـ 0x80070005 إلى رقم خطأ Win32 5.
4.3. أهم نمط: 0x8007xxxx = HRESULT_FROM_WIN32
لنقل فشل من طبقة أدنى لا تستطيع إعادة إلا رمز خطأ Win32 إلى طبقة أعلى تعيد HRESULT (طريقة COM أو زمن تشغيل .NET)، يوفّر winerror.h الماكرو HRESULT_FROM_WIN32.4 السلوك «خزّن رمز خطأ Win32 في الـ 16 بت الدنيا، اضبط Facility إلى FACILITY_WIN32 (7)، واضبط بت S إلى 1».
flowchart TB
accTitle: كيف يعمل HRESULT_FROM_WIN32
accDescr: خزّن رمز خطأ Win32 في الـ 16 بت الدنيا، اضبط Facility إلى 7 وبت S إلى 1، واجمع HRESULT 0x8007xxxx
win["رمز خطأ Win32(مثال: 5)"] --> low["التخزين في الـ 16 بت الدنيا"]
low --> fac["ضبط Facility إلى 7"]
fac --> sbit["ضبط بت S إلى 1"]
sbit --> hr["0x80070005"]
الشكل 9: HRESULT_FROM_WIN32 يخزّن خطأ Win32 في الـ 16 بت الدنيا ويضبط Facility=7 وبت S.
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 بت الدنيا في PowerShell.
0x80070005 -band 0xFFFF # 5 → ERROR_ACCESS_DENIED
0x80072EE7 -band 0xFFFF # 12007 → ERROR_INTERNET_NAME_NOT_RESOLVED (WinINet)
كما في المثال الثاني، أخطاء WinINet وWinHTTP (نطاق الرموز 12000) معرّفة أيضاً في فضاء رموز خطأ Win321، لذا يمكن تفكيك 0x8007xxxx شبكي بالإجراء نفسه. إدخال «عندما ترى 0x8007 حوّل الأرقام الأربعة الدنيا إلى عشري» في الذاكرة العضلية هو المهارة العملية الأولى التي يريد هذا المقال أن تأخذها معك.
هناك التحفّظ المعاكس لـ 0x8004xxxx (FACILITY_ITF). لرمز FACILITY_ITF طرف يعرّف المعنى يختلف لكل واجهة، لذا قد تعني القيمة نفسها ذات 32 بت شيئاً مختلفاً إن اختلف الطرف الذي أعادها.5 لـ 0x8004xxxx غير مألوف ابحث لا في بحث عام بل في وثائق المكوّن الذي أعاده (مكتبة، SDK برنامج تشغيل، منتج خادم).
flowchart TB
accTitle: كيف تبحث يتغيّر بين 0x8007 و0x8004
accDescr: FACILITY_WIN32 0x8007xxxx يُقرأ بتفكيك آلي للـ 16 بت الدنيا، أما FACILITY_ITF 0x8004xxxx فطرف تعريف المعنى يختلف لكل واجهة لذا ابحث في مواد المكوّن المعيد
hr{"المرفق هو؟"} -->|7, WIN32| w["حوّل الـ 16 بت الدنيا إلى عشري"]
hr -->|4, ITF| i["المعنى يختلف حسب الطرف المعيد"]
w --> ww["اقرأه كخطأ Win32"]
i --> ii["ابحث في مواد الطرف المعيد"]
الشكل 10: 0x8007xxxx يُفكَّك آلياً؛ 0x8004xxxx يُبحث في مواد المكوّن المعيد.
5. NTSTATUS — رموز طبقة النواة وعالم التعطّل
5.1. التخطيط والخطورة
NTSTATUS رمز ذو 32 بت تستخدمه النواة وبرامج تشغيل الأجهزة وواجهات ntdll الأصلية، وتخطيطه يشبه HRESULT دون أن يكون هو نفسه.3
| موضع البت | الاسم | المعنى |
|---|---|---|
| 31–30 | Sev | الخطورة. 00 = نجاح، 01 = معلومات، 10 = تحذير، 11 = خطأ |
| 29 | C | بت العميل |
| 28 | N | محجوز (0، حتى يكون الربط إلى HRESULT ممكناً) |
| 27–16 | Facility | المرفق (12 بت) |
| 15–0 | Code | رمز التفصيل |
لأن الخطورة بتّان، تقرأ النوع من الرقم السداسي الأمامي. 0xC… خطأ (11)، 0x8… تحذير (10)، 0x4… معلومات (01)، 0x0–0x3… نجاح. استثناء نقطة التوقّف 0x80000003 (STATUS_BREAKPOINT) مثال تمثيلي لـ«تحذير لا خطأ».37
flowchart TB
accTitle: يُقرأ NTSTATUS بالنوع من الرقم الأمامي
accDescr: لأن الخطورة بتّان يُقرأ NTSTATUS كخطأ إن كان الرقم السداسي الأمامي 0xC، وتحذير إن 0x8، ومعلومات إن 0x4، ونجاح إن 0x0 إلى 0x3
head{"الرقم السداسي الأمامي؟"} -->|0xC| e["خطأ"]
head -->|0x8| w["تحذير"]
head -->|0x4| i["معلومات"]
head -->|0x0–0x3| s["نجاح"]
w -.-> ex["مثال: 0x80000003 تحذير"]
الشكل 11: يُقرأ NTSTATUS بالنوع من الرقم السداسي الأمامي. 0x80000003 «تحذير لا خطأ».
5.2. أين تقابله — رموز الاستثناء ورموز STOP وسجلّ الأحداث
المواقف التي يقابل فيها موظفو تقنية المعلومات والمطوّرون NTSTATUS مرتبطة أساساً بالتعطّل.
- رمز استثناء تعطّل تطبيق: «Exception code: 0xc0000005» المسجَّل في سجلّ الأحداث تحت «خطأ تطبيق (معرّف الحدث 1000)» هو NTSTATUS. القيم التمثيلية كالتالي.7
| القيمة | الرمز | المعنى |
|---|---|---|
| 0xC0000005 | STATUS_ACCESS_VIOLATION | انتهاك وصول (وصول غير قانوني إلى الذاكرة) |
| 0xC0000135 | STATUS_DLL_NOT_FOUND | DLL مطلوبة غير موجودة ولا يمكن البدء |
| 0xC00000FD | STATUS_STACK_OVERFLOW | فيضان المكدّس |
| 0xC0000374 | STATUS_HEAP_CORRUPTION | فساد الكومة |
- رمز STOP الشاشة الزرقاء: تبدوان متشابهين للوهلة الأولى، لكن رمز STOP (رمز فحص عطب) نظام ترقيم خاص به منفصل عن NTSTATUS، مثل 0x0000009F (DRIVER_POWER_STATE_FAILURE)، وله مرجع مخصّص.14 يكفي تذكّر التمييز «0xC0000005 هو NTSTATUS؛ STOP 0x9F رمز فحص عطب ولا يجوز البحث عنه في جدول NTSTATUS».
- عمود Result في Process Monitor: NAME NOT FOUND وACCESS DENIED في عمود Result في Procmon أسماء عرض لـ NTSTATUS الذي أعادته النواة (STATUS_OBJECT_NAME_NOT_FOUND وSTATUS_ACCESS_DENIED). وهو أيضاً موضع تشعر فيه بتقابل الطبقات: مراقبة فشل إدخال/إخراج ملف بمفردات NTSTATUS ثم تحويل ذلك الفشل إلى خطأ Win32 ووصوله إلى التطبيق.
flowchart TB
accTitle: تمييز رمز استثناء عن رمز STOP
accDescr: اقرأ رمز استثناء سجلّ الأحداث كـ NTSTATUS؛ ابحث عن رمز STOP الشاشة الزرقاء في مرجع رموز فحص العطب المخصّص، نظام آخر
q{"أين ظهر الرمز؟"} -->|رمز استثناء| nt["اقرأه كـ NTSTATUS"]
q -->|رمز STOP| bc["ابحث في جدول رموز فحص العطب"]
nt -.-> n1["مثال: 0xC0000005"]
bc -.-> b1["مثال: 0x0000009F"]
الشكل 12: رمز استثناء سجلّ الأحداث NTSTATUS؛ رمز STOP الشاشة الزرقاء نظام آخر. لا تبحث عنهما في الجدول الخطأ.
التحقيق وراء رمز الاستثناء، أي التقاط ملفّ تفريغ وتحليله، مشروح في «جمع crash dumps لتطبيقات Windows» و«قراءة ملفّات تفريغ الأعطال عبر WinDbg + SOS».
5.3. العلاقة بـ HRESULT — بت N وRtlNtStatusToDosError
الجسر بين NTSTATUS والطبقتين الأخريين له مساران.
- ربط في فضاء HRESULT: ضبط بت N في HRESULT (0x10000000) يدخل قيمة NTSTATUS إلى فضاء HRESULT كما هي (الماكرو HRESULT_FROM_NT في winerror.h). ربط 0xC0000005 يصبح مثلاً 0xD0000005. عندما ترى HRESULT يبدأ بـ 0xD، الإجراء الصحيح هو نزع بت N وقراءته كـ NTSTATUS.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). من المفيد أيضاً تذكّر أن مفردات النواة الغنية تُقرَّب أحياناً في طبقة Win32 إلى تمييز أخشن.
flowchart TB
accTitle: جسران من NTSTATUS إلى الطبقات الأخرى
accDescr: يُمرَّر NTSTATUS إلى الطبقات الأخرى بطريقتين: الربط في فضاء HRESULT بضبط بت N، والتحويل إلى رمز خطأ Win32 عبر RtlNtStatusToDosError
nt["NTSTATUS(0xC0000005)"] -->|ضبط بت N| hr["HRESULT(0xD0000005)"]
nt -->|RtlNtStatusToDosError| win["خطأ Win32 998(ERROR_NOACCESS)"]
win -.-> memo["ERROR_MR_MID_NOT_FOUND إن لم يُعرَّف تقابل"]
الشكل 13: جسرا NTSTATUS اثنان. بداية 0xD تُقرأ كـ NTSTATUS بعد نزع بت N.
6. COM و.NET — كيف يُربط رمز خطأ باستثناء
6.1. أسلوب COM — HRESULT + IErrorInfo
طريقة COM تعيد أساساً HRESULT، لكن هناك حدّاً لما يُحزَم في 32 بت، لذا كمكمل يمكن لآلية IErrorInfo نقل سلسلة وصف الخطأ والأصل بشكل منفصل. في C++ تعالج الفئة المدعومة من المترجم _com_error HRESULT وIErrorInfo معاً. تطبيق يظهر مربع خطئه «رمزاً + وصفاً» غالباً يحمل الوصف عبر هذه الآلية.
flowchart TB
accTitle: IErrorInfo الذي يكمّل HRESULT
accDescr: هناك حدّ لما يُحزَم في HRESULT ذي 32 بت، لذا تُنقل سلسلة وصف الخطأ والأصل بشكل منفصل بـ IErrorInfo، وفي C++ تعالج الفئة _com_error كليهما معاً
hr["HRESULT(32 بت فقط)"] --> lim["هناك حدّ لما يُحزَم"]
lim --> ei["IErrorInfo يحمل الوصف"]
ei --> ce["_com_error يعالجهما معاً"]
ce -.-> dlg["رمز + وصف المربع"]
الشكل 14: سلسلة وصف لا تتسع في HRESULT ذي 32 بت يحملها IErrorInfo بشكل منفصل.
6.2. أسلوب .NET — من HRESULT إلى نوع استثناء
عندما يستقبل زمن تشغيل .NET فشل HRESULT في COM interop، يحوّله إلى استثناء. HRESULT معروف يُربط بنوع الاستثناء المقابل؛ المجهول يصبح COMException.11
flowchart TB
accTitle: الربط من HRESULT إلى استثناء .NET
accDescr: HRESULT فشل مستقبَل في COM interop يُحوَّل إلى نوع الاستثناء المقابل إن عُرف أو إلى COMException إن جُهل، وفي الحالين تبقى القيمة الأصلية في Exception.HResult
hr["HRESULT فشل"] --> known{"ربط معروف؟"}
known -->|Yes| typed["التحويل إلى نوع الاستثناء المقابل"]
known -->|No| comex["التحويل إلى COMException"]
typed --> keep["القيمة الأصلية تبقى في Exception.HResult"]
comex --> keep
الشكل 15: يربط .NET HRESULT بنوع استثناء، وتبقى القيمة الأصلية في Exception.HResult على كل استثناء.
| HRESULT | نوع استثناء .NET |
|---|---|
| E_ACCESSDENIED (0x80070005) | UnauthorizedAccessException |
| E_OUTOFMEMORY (0x8007000E) | OutOfMemoryException |
| E_INVALIDARG (0x80070057) | ArgumentException |
| E_NOTIMPL (0x80004001) | NotImplementedException |
| قيمة بلا ربط معرَّف | COMException (القيمة الأصلية في الخاصية ErrorCode) |
على كل استثناء يبقى HRESULT الأصلي في الخاصية Exception.HResult. فرعاً في معالجة استثناءات إدخال/إخراج الملفات مثل «أعد المحاولة فقط عند انتهاك مشاركة» يمكن كتابته بهذه القيمة.
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 مباشرة عبر P/Invoke، حدّد SetLastError = true على DllImport (أو LibraryImport)، ثم استرجع بـ Marshal.GetLastWin32Error (من .NET 6 المكافئ GetLastPInvokeError). تعريف GetLastError نفسه كـ P/Invoke واستدعاؤه غير دقيق، لأن استدعاء واجهة داخل زمن التشغيل قد يكتب فوق القيمة.15
flowchart TB
accTitle: استرجاع آخر خطأ في P/Invoke
accDescr: تحديد SetLastError كـ true والاسترجاع بـ Marshal.GetLastWin32Error صحيح؛ استدعاء GetLastError مباشرة عبر P/Invoke غير دقيق بسبب كتابة زمن التشغيل فوقه
pi["استدعاء واجهة Win32 عبر P/Invoke"] --> ok["تحديد SetLastError=true"]
ok --> get["الاسترجاع بـ GetLastWin32Error"]
pi --> ng["تعريف يستدعي GetLastError مباشرة"]
ng --> bad["زمن التشغيل يكتب فوقه وهو غير دقيق"]
الشكل 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، لذا يمكنك استخدامه كما هو لترك الرمز والرسالة معاً في سجلّ. سؤال التصميم: في أي طبقة تلتقط استثناء وكيف تتركه في سجلّ، مشروح في «أين يجب التقاط الاستثناءات وتسجيلها ومعالجة الأخطاء».
7. أدوات التحويل والتحقيق عملياً — مرجع سريع للنسخ واللصق
7.1. err.exe (Microsoft Error Lookup Tool)
أداة بحث عن الأخطاء مستقلة توزّعها Microsoft. تمشي عدداً كبيراً من ملفات الرأس مثل winerror.h وntstatus.h وتسرد تعريفات ورسائل تطابق الرمز المحدّد.8
err 0x80070005
err 5
err 0xC0000005
رقم واحد قد يصيب في عدة رؤوس (مثلاً «5» يطابق تعريفات في مواضع شتى غير Win32 ERROR_ACCESS_DENIED)، لذا أي المرشّحين معقول يجب اختياره بالسياق. اسم ملف التنزيل مُصدَّر (Err_6.4.5.exe وقت الكتابة)، ولاحظ أيضاً أن تعريفات الرموز تستند إلى الرؤوس وقت الحزم.8
flowchart TB
accTitle: اختر نتائج بحث err.exe بالسياق
accDescr: يمشي err.exe عدداً كبيراً من ملفات الرأس ويسرد التعريفات المطابقة، لذا عندما يظهر عدة مرشّحين للرقم نفسه اختر المعقول بالسياق
in["أدخل err 5"] --> scan["المشي على عدد كبير من الرؤوس"]
scan --> hits["عدة تعريفات أصابت"]
hits --> pick["اختيار مرشّح معقول بالسياق"]
الشكل 17: err.exe بحث عبر الرؤوس، لذا قد يظهر عدة مرشّحين، ويُختار المعقول بالسياق.
7.2. أوامر مدمجة في ويندوز
ما يمكنك استخدامه بلا تثبيت إضافي certutil وnet helpmsg. خيار -error في certutil يعرض نص الرسالة المقابل لرمز خطأ، ويقبل إما HRESULT سداسياً أو عشرياً.9
certutil -error 0x80070005
certutil -error 5
net helpmsg 5
net helpmsg لرمز خطأ Win32 عشري فقط، لكن في بيئة عربية تعود الرسالة بالعربية، لذا يمكنك استخدامها كما هي لشرح للمستخدم.
flowchart TB
accTitle: كيف تختار بين الأوامر القياسية
accDescr: رمز خطأ Win32 عشري يُبحث بـ net helpmsg؛ رمز يشمل سداسياً بما فيه HRESULT يُبحث بخيار -error في certutil
q{"الرمز الذي لديك؟"} -->|Win32 عشري| net["net helpmsg"]
q -->|يشمل سداسياً| cert["certutil -error"]
net -.-> jp["تعود رسالة عربية"]
cert -.-> any["يقبل السداسي والعشري"]
الشكل 18: كيف تختار بين الأوامر القياسية. خطأ Win32 عشري هو net helpmsg؛ إن شمل سداسياً فـ certutil -error.
7.3. مجموعة أسطر 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
للبحث عن رمز أثناء تحليل التفريغ، امتداد !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>
في ملفّ تفريغ يعرض !analyze -v تلقائياً رمز الاستثناء (NTSTATUS)، لذا التدفّق تأكيد المعنى من هناك بـ !error <code> 1.
flowchart TB
accTitle: تدفّق تأكيد رمز استثناء في WinDbg
accDescr: في ملفّ تفريغ يعرض أمر analyze تلقائياً رمز الاستثناء؛ مرّر ذلك الرمز إلى امتداد error بوسيط ثانٍ 1 وأكّد المعنى كـ NTSTATUS
dump["فتح ملفّ التفريغ"] --> an["تشغيل !analyze -v"]
an --> exc["يُعرض رمز الاستثناء"]
exc --> chk["تأكيد المعنى بـ !error code 1"]
الشكل 19: في تحليل التفريغ ابحث عن رمز الاستثناء الذي عرضه !analyze -v بـ !error والعلم 1.
8. إجراء تحقيق — من الحكم على الطبقة إلى المطابقة مع السياق
اجمع المعرفة حتى الآن في إجراء لتحقيق رمز خطأ فعلاً.
- طبّع الكتابة. إن كان عشرياً سالباً حوّله إلى سداسي من 8 أرقام. املأ بالصفر سداسياً أقصر من 8 أرقام واقرأه.
- احكم أي طبقة الرمز. كما في جدول الحكم أدناه، الأرقام الأمامية القليلة تقرّر تقريباً.
- فكّك واستخرج الرمز الجوهري. عملية آلية: الـ 16 بت الدنيا إن 0x8007xxxx، نزع بت N إن 0xDxxxxxxx.
- ابحث عن الاسم والتعريف بأداة. أكّد اسم الرمز والرسالة بـ err.exe أو certutil أو
!error. - طابقه مع السياق. حدّد أي تطبيق وأي عملية وأي واجهة فشلت ضد ماذا، من سجلّ التطبيق وسجلّ الأحداث وProcmon. الرمز «نوع الفشل»؛ السياق «موضع السبب».
flowchart TB
accTitle: إجراء تحقيق رمز خطأ
accDescr: نمط التحقيق بمحاذاة الكتابة إلى السداسي والحكم على الطبقة من الأرقام الأمامية والتفكيك واستخراج الرمز الجوهري والبحث عن الاسم والتعريف بأداة ثم المطابقة مع السياق
fix["التطبيع إلى سداسي"] --> judge{"الأرقام الأمامية؟"}
judge -->|عشري| d1["القراءة كخطأ Win32"]
judge -->|0x8007| d2["الـ 16 بت الدنيا → عشري"]
judge -->|0xC| d3["القراءة كـ NTSTATUS"]
judge -->|0xD| d4["نزع بت N والقراءة"]
d1 --> tool["البحث عن الاسم/التعريف"]
d2 --> tool
d3 --> tool
d4 --> tool
tool --> ctx["مطابقة السياق(Procmon)"]
الشكل 20: نمط التحقيق. طبّع الكتابة، احكم على الطبقة وفكّك، ابحث عن الاسم، ثم طابق مع السياق.
| المظهر | المرشّح الأول | كيف تفكّك وتحوّل |
|---|---|---|
| عشري من 1 إلى 5 أرقام (5 و1223 وما شابه) | رمز خطأ Win32 | كما هو إلى net helpmsg أو err.exe |
| عشري سالب (-2147024891 وما شابه) | HRESULT | حوّل إلى سداسي من 8 أرقام ثم حكم الصفوف أدناه |
| 0x8007xxxx | HRESULT (FACILITY_WIN32) | حوّل الـ 16 بت الدنيا إلى عشري واقرأ كـ Win32 |
| 0x8004xxxx | HRESULT (FACILITY_ITF) | ابحث في وثائق المكوّن المعيد |
| 0x8000xxxx | HRESULT (FACILITY_NULL) | رمز عام مثل E_FAIL. انقل الوزن إلى تحقيق سياق |
| 0xCxxxxxxx | NTSTATUS (خطأ) | !error <code> 1؛ حوّل إلى Win32 واقرأ إن لزم |
| 0xDxxxxxxx | ربط NTSTATUS في HRESULT | انزع بت N (0x10000000) واقرأ كـ NTSTATUS |
| مرفق خاص مثل 0x8024xxxx | HRESULT خاص بمنطقة ميزة | حدّد المنطقة من قيمة Facility واذهب إلى مواد مخصّصة (0x8024… هو Windows Update)2 |
ما هو فعّال خاصة في الخطوة 5 «المطابقة مع السياق» عمود Result في Process Monitor. حتى إن أظهر التطبيق فقط «0x80070002»، يخبرك Procmon في صف واحد «أي عملية، ضد أي مسار، أُعيد إليها NAME NOT FOUND». للبحث من جهة سجلّ الأحداث انظر أيضاً «مدخل إلى سجلّ أحداث Windows وETW».
9. قراءات خاطئة شائعة — أنماط تطيل طريق التحقيق
أخيراً أنماط قراءة خاطئة تظهر في استشارات فعلية.
قراءة خاطئة 1: الظن أن 0x80004005 «رمز يشير إلى سبب محدّد»
E_FAIL هو «Unspecified failure»، والقيمة نفسها تظهر في Windows Update والشبكة وقواعد البيانات. تجربة كل علاج يظهر عند البحث بهذا الرمز طريق طويل شبه مؤكد. ضيّق لا من الرمز بل من «أي تطبيق، أي عملية، سجلات أخرى في الوقت نفسه».6
قراءة خاطئة 2: عدم ملاحظة أن العشري السالب HRESULT
حالة البحث في سجلّ يقول «Error -2147467259 occurred» كما هو، أو الحيرة من «خطأ بناقص؟». عندما ترى سالباً حوّله إلى سداسي. ذلك وحده يخبرك أنه 0x80004005 (E_FAIL)، ويتصل بمعرفة القراءة الخاطئة 1.
قراءة خاطئة 3: البحث عن الـ 8 أرقام كاملة لـ 0x8007xxxx دون النظر إلى خطأ Win32 التحتي
جوهر 0x80070005 هو «5 = رُفض الوصول». التفكير بعد استخراج الـ 16 بت الدنيا في «ماذا يعني خطأ Win32 5 في سياق هذه العملية» يصل إلى اللب أسرع من البحث بالـ 8 أرقام كاملة.
قراءة خاطئة 4: افتراض «الرمز نفسه = السبب نفسه»
إن مرّ بك مرة «الخطأ 5 سببه مضاد فيروسات» تميل إلى القفز إلى العلاج نفسه عند الخطأ 5 التالي. حتى مع الرمز نفسه، إن اختلفت الواجهة التي فشلت والمورد المستهدف فالسبب شيء آخر. تأكيد معنى الرمز وتحديد الهدف بـ Procmon أو ما شابه زوج، في كل مرة.
قراءة خاطئة 5: خلط خطأ Win32 5 مع 0xC0000005 ورمز STOP مع NTSTATUS
معاملة ERROR_ACCESS_DENIED وSTATUS_ACCESS_VIOLATION كأنهما واحد بسبب صلة «5» يرسل التحقيق في اتجاهين مختلفين تماماً — مشكلة صلاحيات مقابل عيب برمجي. أيضاً رمز STOP الشاشة الزرقاء نظام آخر غير NTSTATUS، لذا البحث عن 0x9F في جدول NTSTATUS لا ينتج إجابة ذات معنى.14
flowchart TB
accTitle: الخطأ 5 و0xC0000005 لهما اتجاها تحقيق مختلفان
accDescr: ينبغي تحقيق خطأ Win32 5 كمشكلة صلاحيات وNTSTATUS 0xC0000005 كعيب برمجي؛ معاملتهما واحداً يرسل التحقيق في اتجاه آخر
a["خطأ Win32 5"] --> ad["تحقيق مشكلة صلاحيات"]
b["NTSTATUS 0xC0000005"] --> bd["تحقيق عيب برمجي"]
a -.-> memo["رموز لا صلة بينها من نظامين مختلفين"]
b -.-> memo
الشكل 21: لا تعاملها واحداً بسبب صلة «5». الخطأ 5 يتجه إلى مشكلة صلاحيات؛ 0xC0000005 إلى عيب برمجي.
10. الخلاصة
- رموز أخطاء ويندوز بنية ثلاثية الطبقات من رموز خطأ Win32 وHRESULT وNTSTATUS. احكم أولاً أي طبقة وأي طرف أعاد الرمز.
- تذبذب الكتابة (عشري / سداسي / سالب) يمكن محاذاته آلياً. حوّل السالب إلى سداسي من 8 أرقام ثم اقرأه.
- HRESULT بنية بتات S/R/C/N/X + Facility (11 بت) + Code (16 بت)، و0x8007xxxx أهم نمط، خطأ Win32 ملفوف. حوّل الـ 16 بت الدنيا إلى عشري واستخرج الرمز الجوهري.
- رمز عام مثل 0x80004005 (E_FAIL) لا يشير إلى سبب. الحكم بالتوقف عن الحفر في الرمز والانتقال إلى تحقيق سياق ممكن تحديداً لأنك تعرف البنية.
- تقابل NTSTATUS كرمز استثناء تعطّل أو في عمود Result في Procmon. 0xC0000005 انتهاك وصول لا صلة له بخطأ Win32 5. رمز STOP نظام آخر أيضاً.
- في .NET يُربط HRESULT بنوع استثناء، وتبقى القيمة الأصلية في Exception.HResult. في P/Invoke استخدم SetLastError=true وMarshal.GetLastWin32Error كزوج.
- أدوات البحث certutil -error وnet helpmsg (قياسية)، وerr.exe (آلة تطوير)، وأسطر PowerShell واحدة، و!error في WinDbg.
- الإجراء «طبّع الكتابة → احكم على الطبقة → فكّك → ابحث عن الاسم → طابق مع السياق». ما يخبرك به الرمز نوع الفشل؛ موضع السبب ما يخبرك به السياق.
في المرة التالية التي تقابل فيها رمز خطأ غير مألوف، انظر إلى الأرقام الأمامية القليلة قبل لصقه في مربع البحث. الأرقام الأربعة الدنيا إن 0x8007، وNTSTATUS إن 0xC، والتحويل إلى سداسي إن سالب — هذا التفكيك في 10 ثوانٍ يقرّر إلى حد بعيد زمن التحقيق الذي يلي.
مقالات ذات صلة
- قراءة ملفّات تفريغ الأعطال عبر WinDbg + SOS ── مدخل عمليّ للتحليل بعد الجمع
- جمع crash dumps لتطبيقات Windows: متى تبدأ بـ WER أو ProcDump أو WinDbg
- أين يجب التقاط الاستثناءات وتسجيلها ومعالجة الأخطاء - دليل عمليّ للحدود والمسؤوليّات في تسلسل الاستدعاء
- دليل عملي لأداة Process Monitor (ProcMon) — تحديد سبب «عدم قراءة الإعدادات» و«ACCESS DENIED» خلال 10 دقائق
- مدخل إلى سجلّ أحداث Windows وETW ── وضع سجلّات تطبيق الأعمال على آليّة نظام التشغيل القياسيّة
مجالات الاستشارة ذات الصلة
تتولّى شركة كومورا سوفت ذ.م.م. التحقيق في الحوادث الذي يبدأ من رمز خطأ — «لا أعرف ماذا يعني هذا الرمز»، «0x80070005 يظهر فقط في بيئة معيّنة» — وتصميم معالجة الأخطاء لتطبيقات تمزج Win32 API وCOM و.NET، وتحديد الأسباب بملفات التفريغ وProcess Monitor. استشارة من لقطة شاشة واحدة لمربع حوار خطأ مناسبة.
- تطوير تطبيقات Windows
- التحقيق في الأخطاء وتحليل الأسباب الجذريّة
- الاستشارة التقنيّة ومراجعة التصميم
- تواصل معنا
روابط مرجعيّة
-
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 -
Microsoft Open Specifications, [MS-ERREF]: HRESULT. تخطيط بتات HRESULT (بتات S وR وC وN وX، Facility ذو 11 بت، Code ذو 16 بت)؛ وأن بت N يشير إلى قيمة NTSTATUS مربوطة في فضاء HRESULT؛ وقائمة رموز المرفق بما فيها FACILITY_WINDOWS_UPDATE (36). ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Open Specifications, [MS-ERREF]: NTSTATUS. تخطيط بتات NTSTATUS (Sev ذو بتّين، بت C، بت N، Facility ذو 12 بت، Code ذو 16 بت)؛ وأن الخطورة تنقسم إلى أربعة أنواع: نجاح (00) ومعلومات (01) وتحذير (10) وخطأ (11). ↩ ↩2 ↩3
-
Microsoft Learn, HRESULT_FROM_WIN32 macro. تعريف ماكرو winerror.h الذي يربط رمز خطأ نظام Win32 بقيمة HRESULT. ↩ ↩2 ↩3
-
Microsoft Learn, Structure of COM Error Codes. دور بت خطورة HRESULT وحقل المرفق؛ قيم FACILITY_NULL وFACILITY_RPC وFACILITY_ITF وFACILITY_WIN32 وFACILITY_WINDOWS؛ وأن رمز FACILITY_ITF معناه معرَّف لكل واجهة وقد تعني القيمة نفسها شيئاً مختلفاً. ↩ ↩2 ↩3
-
Microsoft Learn, Common HRESULT values. أن E_FAIL (0x80004005) هو «Unspecified failure»؛ وتعريفات قيم HRESULT شائعة مثل E_ACCESSDENIED (0x80070005) وE_INVALIDARG (0x80070057) وE_OUTOFMEMORY (0x8007000E). ↩ ↩2 ↩3 ↩4
-
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
-
Microsoft Learn, The Microsoft Error Lookup Tool. أنها أداة مستقلة تعرض نص الرسالة المرتبط برمز حالة سداسي عبر ملفات رأس شتى مثل Winerror.h؛ وأن اسم ملف التنزيل Err_6.4.5.exe؛ وأنك تحتاج إلى ملاحظة أن التعريفات المعبأة كما في وقت الترجمة. ↩ ↩2 ↩3
-
Microsoft Learn, certutil. أن خيار -error في certutil يعرض نص الرسالة المرتبط برمز خطأ، وأن كتابة خطأ تشمل اسم رمز تُستخدم بشكل مثل 0x80070002 (WIN32: 2 ERROR_FILE_NOT_FOUND). ↩ ↩2
-
Microsoft Learn, !error. أن امتداد !error في WinDbg يفكّ ويعرض قيم أخطاء Win32 وWinsock وNTSTATUS وNetAPI؛ وأن تحديد 1 كعلم يفسّر كـ NTSTATUS. ↩ ↩2
-
Microsoft Learn, How to: Map HRESULTs and exceptions. آلية الربط المتبادل بين HRESULT COM واستثناءات .NET؛ جدول التقابل مثل E_NOTIMPL → NotImplementedException؛ وأن HRESULT بلا ربط صريح يُحوَّل إلى COMException؛ وأن Message وSource وما شابه للاستثناء تُهيَّأ من معلومات IErrorInfo. ↩ ↩2
-
Microsoft Learn, RtlNtStatusToDosError function (winternl.h). أنها دالة تحوّل رمز NTSTATUS إلى رمز خطأ نظام Win32 المقابل؛ وأن ERROR_MR_MID_NOT_FOUND يُعاد عندما لا يُعرَّف تقابل؛ وأنه لا توجد دالة تحويل عكسي. ↩ ↩2
-
Microsoft Learn, Last-Error Code. أن last-error code يُحفظ لكل خيط؛ وأنه ينبغي استرجاعه بـ GetLastError فوراً بعد الفشل؛ وأن واجهات تكتب فوق الرمز بـ 0 عند النجاح وواجهات لا تمسّه مختلطة؛ وأن البت 29 محجوز لرموز يعرّفها التطبيق. ↩ ↩2
-
Microsoft Learn, Bug check code reference. قائمة رموز فحص العطب (رموز STOP) المعروضة على شاشة زرقاء، وكيف تعرض معلومات عن رمز بامتداد !analyze في WinDbg. أنه نظام ترقيم خاص به منفصل عن NTSTATUS يمكن تأكيده من القائمة. ↩ ↩2
-
Microsoft Learn, Marshal.GetLastWin32Error Method. أنها طريقة لاسترجاع last-error code لاستدعاء P/Invoke ضبط علم SetLastError؛ وأن استدعاء GetLastError مباشرة عبر P/Invoke غير موثوق بسبب الكتابة فوقه باستدعاء واجهة داخل زمن التشغيل؛ وأنه من .NET 6 يُوصى بـ GetLastPInvokeError. ↩
مقالات ذات صلة
أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.
واجهة مجمع مؤشّرات الترابط Win32 ── تزامن دون إنشاء مؤشّرات ترابط، عبر CreateThreadpoolWork
هل تنثر استدعاءات CreateThread في شيفرتك الأصليّة؟ يشرح هذا المقال واجهة مجمع مؤشّرات الترابط Win32 التي أُعيد تصميمها في Vista ── كائنات...
الأنابيب المسمّاة عمليّاً ── IPC القياسيّ في Windows من التصميم إلى الأمان
دليل عمليّ للأنابيب المسمّاة، وسيلة الاتّصال القياسيّة بين العمليّات في Windows. ينظّم المقال، من المصادر الأوّليّة، الاختيار بين وضع الب...
تطبيقات تتعطّل عند الاستئناف من السكون ── كيف تعمل أحداث الطاقة في Windows وكيف تبني تطبيقات أعمال تصمد أمامها
فتحت الحاسوب المحمول فوجدت اتّصالات تطبيق الأعمال ميّتة ── السبب تصميم لم يحسب حساب السكون. يغطّي المقال تدفّق إشعار WM_POWERBROADCAST، و...
DllMain وقفل المحمِّل ── السبب الحقيقي لعبارة «لا تفعل شيئاً في تهيئة الـDLL»
لماذا يجب ألا تستدعي LoadLibrary أو تتزامن مع مؤشّرات ترابط أخرى من DllMain. يستند المقال إلى المصادر الأوّليّة ليشرح كيف يسلسل قفل المحم...
ما الذي يعنيه «لا يستجيب» حقّاً ── كيف يقرِّر Windows أنّ تطبيقاً قد تجمّد، وكيف تصمِّم تطبيقات لا تتجمّد
«لا يستجيب» في Windows آليّة يحكم فيها نظام التشغيل أنّ نافذة لم تسترجع رسالة لمدّة 5 ثوانٍ ويستبدلها بنافذة شبح. يغطّي المقال دواخل ذلك ...
أين يتصل هذا الموضوع
ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.
تطوير تطبيقات ويندوز
ندعم تطوير برامج ويندوز للأعمال، وتكامل الأجهزة، وأدوات التواصل.
الأسئلة الشائعة
أسئلة شائعة حول موضوع هذه المقالة.
- ماذا يعني الخطأ 0x80004005؟
- 0x80004005 هو HRESULT E_FAIL، ويعني «Unspecified failure» (فشل غير محدّد). أي أنه يشير فقط إلى أن «فشلاً وقع ولا يستطيع الإبلاغ عن سبب تفصيلي»؛ وليس رمزاً يمثّل السبب نفسه. يظهر 0x80004005 نفسه في مواضع لا صلة بينها — الشبكة، Windows Update، VBA، برنامج تشغيل قاعدة بيانات — لهذا السبب. عندما ترى هذا الرمز، لا تحفر في معنى الرمز؛ ضيّق السبب من سياق أي تطبيق وأي عملية أنتجته، ومن معلومات الخطأ الأخرى في سجلّ الأحداث أو سجلّ تفصيلي.
- ما رمز الخطأ السالب مثل -2147467259؟
- هو HRESULT ذو 32 بت معروض كعدد عشري موقّع. يضبط HRESULT البت الأعلى عند الفشل، لذا كعدد صحيح موقّع يكون دائماً سالباً. في PowerShell، '0x{0:X8}' -f -2147467259 يعيده إلى سداسي عشري (في هذا المثال 0x80004005 = E_FAIL). عندما ترى عدداً سالباً يبدأ بـ -214… في سجلّ أو رسالة خطأ لسكربت، الخطوة الأولى القياسية هي تحويله إلى سداسي ثم البحث.
- ما أسهل طريقة للبحث عن معنى رمز خطأ؟
- بلا تثبيت إضافي استخدم net helpmsg 5 في موجه الأوامر (لخطأ Win32 عشري) وcertutil -error 0x80070005. يقبل certutil أيضاً HRESULT سداسياً ويعرض اسم الرمز ونص الرسالة. في PowerShell، [System.ComponentModel.Win32Exception]::new(5).Message يجلب الرسالة المحلّاة. على آلة تطوير احتفظ بأداة Microsoft الرسمية err.exe (Microsoft Error Lookup Tool)؛ تبحث عبر Win32 وHRESULT وNTSTATUS وتسرد التعريفات المطابقة دفعة واحدة.
- أي نوع من الأخطاء هو 0xC0000005؟
- هو NTSTATUS STATUS_ACCESS_VIOLATION، أي انتهاك وصول (وصول غير قانوني إلى الذاكرة). هو الرمز الذي تراه أكثر من غيره كـ «Exception code» في سجلّ الأحداث أو في ملفّ تفريغ عند تعطّل التطبيق، ويدلّ على عيب برمجي مثل إلغاء مرجع مؤشّر غير صالح أو الوصول إلى ذاكرة محرّرة. يشبه بالاسم خطأ Win32 5 (ERROR_ACCESS_DENIED = رُفض الوصول)، لكنه رمز لا صلة له من نظام آخر؛ فلا تخلط بينهما. الطريقة الموثوقة لتحديد السبب هي التقاط ملفّ تفريغ وتحليله في WinDbg.
- لماذا يختلف السبب في كل مرة حتى مع الرمز نفسه؟
- لأن رمز الخطأ يمثّل فقط «أي نوع من الفشل»، و«ما الذي فشل ولماذا» يقرّره سياق الاستدعاء. الخطأ 5 (رُفض الوصول) مثلاً هو الرمز نفسه لأسباب مختلفة تماماً — صلاحيات NTFS غير كافية، امتيازات مسؤول ناقصة، حظر مضاد فيروسات، وهكذا. في وضع مشابه، إذا ظلّت عملية أخرى تفتح الملف تحصل على رمز مختلف (الخطأ 32 = انتهاك مشاركة)، وقراءة الرمز بشكل صحيح تغيّر أين تبحث. الخطأ 2 (الملف غير موجود) غالباً ليس الملف الرئيسي بل DLL تابعة أو ملف إعدادات. بعد البحث عن معنى الرمز، تأكيد أي واجهة فشلت ضد أي مورد عبر Process Monitor أو ما شابه هو الطريق القصير إلى السبب.
الملف الشخصي للمؤلف
صفحة الملف الشخصي لمؤلف المقالة.
غو كومورا
مؤسّس شركة كومورا سوفت ذ.م.م.
يركّز على تطوير برامج ويندوز، والاستشارات التقنية، والتحقيق في الأخطاء، ويتميّز في المشاريع التي تبقى فيها الأصول القديمة ناشطة، وفي تشخيص الأعطال التي يصعب تحديد سببها.