2011-10-27 16 views
11

Tôi miễn cưỡng phải đối phó với các ngoại lệ cấu trúc Win32 một lần nữa. Tôi đang cố gắng tạo ra một chuỗi mô tả một ngoại lệ. Hầu hết nó là đơn giản, nhưng tôi bị mắc kẹt trên một cái gì đó cơ bản: làm thế nào tôi có thể chuyển đổi một mã ngoại lệ (kết quả của GetExceptionCode(), hoặc ExceptionCode thành viên của một EXCEPTION_RECORD) vào một chuỗi mô tả các ngoại lệ?Làm cách nào để chuyển đổi mã ngoại lệ Win32 thành chuỗi?

Tôi đang tìm kiếm thứ gì đó sẽ chuyển đổi ví dụ: 0xC0000005 thành "Vi phạm truy cập". Có phải chỉ là một cuộc gọi đến FormatMessage()?

+0

Có, 'FormatMessage' nên làm các trick. – avakar

Trả lời

3

Có. Đó là một NTSTATUS, vì vậy sử dụng FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_FROM_HMODULE, và vượt qua HMODULE từ LoadLibrary("NTDLL.DLL")

Source

+0

Win32 là một bộ mã lỗi khác. – MSalters

+0

Cảm ơn, điều đó rất gần. Thật không may các chuỗi trong NTDLL.DLL dường như không sử dụng mã định dạng chính xác cho FormatMessage. Chuỗi cho 0xc0000005 là 'Hướng dẫn tại% p tham chiếu bộ nhớ tại% p.', Tôi nghĩ, mà FormatMessage chuyển thành 'Hướng dẫn tại "0x' (sic).Xem thêm [câu hỏi liên quan] này (http://stackoverflow.com/questions/321898/how-to-get-the-name-description-of-an-exception). –

+0

Eh, bạn _did_ chuyển vào địa chỉ thực tế? 'FormatMessage' thấy hai tham số'% p', và đầu ra trông giống như nó không định dạng được địa chỉ đầu tiên. – MSalters

7

mã ngoại lệ có cấu trúc được định nghĩa thông qua số NTSTATUS. Mặc dù ai đó từ MS suggests sử dụng FormatMessage() để chuyển đổi số NTSTATUS thành chuỗi, tôi sẽ không thực hiện việc này. Cờ FORMAT_MESSAGE_FROM_SYSTEM được sử dụng để chuyển đổi kết quả của GetLastError() thành một chuỗi, do đó, nó không có ý nghĩa ở đây. Sử dụng cờ FORMAT_MESSAGE_FROM_HMODULE cùng với ntdll.dll sẽ dẫn đến kết quả không chính xác đối với một số mã. Ví dụ: đối với EXCEPTION_ACCESS_VIOLATION, bạn sẽ nhận được The instruction at 0x, không quá thông tin :).

Khi bạn xem các chuỗi được lưu trữ trong ntdll.dll, điều hiển nhiên là nhiều chuỗi được cho là được sử dụng với hàm printf(), không phải với FormatMessage(). Ví dụ, chuỗi cho EXCEPTION_ACCESS_VIOLATION là:

The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

%0 được xử lý bởi FormatMessage() như dãy thoát nghĩa terminator tin nhắn, không một chèn. Chèn là% 1 đến% 99. Đó là lý do tại sao cờ FORMAT_MESSAGE_IGNORE_INSERTS không tạo ra bất kỳ sự khác biệt nào.

Bạn có thể muốn tải các chuỗi từ ntdll.dll và vượt qua nó để vprintf nhưng bạn sẽ cần phải chuẩn bị lập luận chính xác như các quy định cụ thể chuỗi (ví dụ cho EXCEPTION_ACCESS_VIOLATIONunsigned long, unsigned long, char*). Và cách tiếp cận này có nhược điểm lớn: bất kỳ thay đổi về số lượng, thứ tự hoặc kích thước của đối số trong ntdll.dll có thể phá vỡ mã của bạn.

Vì vậy, việc mã hóa các chuỗi thành mã của riêng bạn an toàn hơn và dễ dàng hơn. Tôi thấy nó nguy hiểm khi sử dụng dây được chuẩn bị bởi người khác mà không có sự phối hợp với tôi :) và hơn nữa cho chức năng khác. Đây chỉ là một khả năng nhiều hơn cho sự cố.

+0

Cảm ơn câu trả lời của bạn! (Mặc dù câu hỏi bây giờ là khá cũ.) Nếu bạn nhìn nhận xét của tôi về câu trả lời khác, bạn sẽ thấy tôi phát hiện ra những vấn đề bạn đề cập đến. Tôi chỉ đặc biệt-cased các thông điệp phiền hà; Tôi nghĩ rằng tôi thích rằng để mã hóa tất cả mọi thứ cứng như bạn đề nghị. (Đặc biệt là vì nhiều lỗi hơn có thể được thêm vào trong tương lai.) –

+0

Đó là vấn đề về hương vị của khóa học. Tôi đã chọn in mã số (hữu ích cho các lỗi mới có thể xảy ra như bạn đã lưu ý), biểu diễn chuỗi của nó (ví dụ: "EXCEPTION_INVALID_DISPOSITION") và các giá trị khác từ cấu trúc EXCEPTION_RECORD. Đối với nhu cầu của tôi là đủ. Tôi không nghĩ rằng nó có ý nghĩa để hiển thị mô tả chi tiết cho người dùng cuối. Hầu hết trong số họ sẽ khó hiểu nó. Và ngay cả đối với những người nâng cao, nó sẽ không hữu ích, họ sẽ không sửa chương trình của bạn. Người dùng cuối chỉ cần chuyển thông tin đó cho nhà phát triển để điều tra. Và tôi là nhà phát triển có thể đọc mô tả cập nhật về mã lỗi trên Internet. – 4LegsDrivenCat

1

Việc xử lý chính xác định dạng luồng một số chuỗi NTSTATUS có. Bạn nên xem xét chuyển đổi nó thành một tin nhắn Win32 với RtlNtStatusToDosError(), mà đi kèm trong tiêu đề Winternl.h. Bạn sẽ cần phải có ntdll.lib trong đầu vào liên kết của bạn.

thực hiện Ví dụ:

// Returns length of resulting string, excluding null-terminator. 
// Use LocalFree() to free the buffer when it is no longer needed. 
// Returns 0 upon failure, use GetLastError() to get error details. 
DWORD FormatNtStatus(NTSTATUS nsCode, TCHAR **ppszMessage) { 

    // Get handle to ntdll.dll. 
    HMODULE hNtDll = LoadLibrary(_T("NTDLL.DLL")); 

    // Check for fail, user may use GetLastError() for details. 
    if (hNtDll == NULL) return 0; 

    // Call FormatMessage(), note use of RtlNtStatusToDosError(). 
    DWORD dwRes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, 
     hNtDll, RtlNtStatusToDosError(nsCode), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
     (LPTSTR)ppszMessage, 0, NULL); 

    // Free loaded dll module and decrease its reference count. 
    FreeLibrary(hNtDll); 

    return dwRes; 
} 
+0

Điều đó sẽ làm gì khi được cấp 0xC0000005? –

+0

@AlanStokes Nó sẽ được chuyển thành ERROR_NOACCESS (Trong bản tiếng Anh: "Truy cập không hợp lệ vào vị trí bộ nhớ"). –