Winapi повідомлення про помилки і обробка повідомлень, tutorial, code q - a російська (ru)

API Windows надається за допомогою C-викликається інтерфейсу. Успіх чи невдача виклику API повідомляються строго через повернені значення. Винятки не є частиною документованого контракту (хоча деякі реалізації API можуть викликати виключення SEH. Наприклад, при передачі аргументу lpCommandLine тільки для читання в CreateProcess).

  • Тільки повертається значення
  • Значення, що повертається з додатковою інформацією про збої
  • Значення, що повертається з додатковою інформацією про відмову і успіху
  • Значення, що повертається HRESULT

Документація для кожного виклику API явно викликається, як повідомляються помилки. Завжди звертайтеся до документації.

Перетворення коду помилки в рядок повідомлення

GetLastError повертає числовий код помилки. Щоб отримати описову повідомлення про помилку (наприклад. Для відображення користувачеві), ви можете викликати FormatMessage.

У C ++ ви можете значно спростити інтерфейс, використовуючи клас std :: string.

ПРИМІТКА. Ці функції також працюють для значень HRESULT. Просто змініть перший параметр з DWORD dwErrorCode на HRESULT hResult. Інша частина коду може залишатися незмінною.

Помилка, повідомлена як значення HRESULT

HRESULT s - числові 32-бітові значення, де біти або діапазони біт кодують чітко визначену інформацію. MSB - це прапор збою / успіху, а інші біт зберігають додаткову інформацію. Відмова або успіх можна визначити за допомогою макросів FAILED або SUCCEEDED. HRESULT s зазвичай використовуються спільно з COM, але також відображаються в реалізаціях, відмінних від COM (наприклад, StringCchPrintf).

Помилка, повідомлена тільки поворотним значенням

Деякі виклики API повертають єдиний прапор відмови / успіху без будь-якої додаткової інформації (наприклад, GetObject):

Повідомляється про помилку з повідомленням про помилку

На додаток до що повертається значенням відмови / успіху деякі виклики API також встановлюють останню помилку при збої (наприклад, CreateWindow). Документація зазвичай містить наступну стандартне формулювання для цього випадку:

Якщо функція завершується успішно, повертається значення <значение успеха API>.
Якщо функція не працює, повертається значення <значение ошибки API>. Щоб отримати розширену інформацію про помилку, викличте GetLastError.

Вкрай важливо, щоб ви негайно GetLastError () НЕГАЙНО. Останній код помилки може бути перезаписан будь-який інший функцією, тому, якщо між невдалої функцією і викликом GetLastError () буде GetLastError () додатковий виклик функції, повернення з GetLastError () більше не буде надійним. Будьте дуже уважні, працюючи з конструкторами C ++.

Як тільки ви отримаєте код помилки, вам потрібно буде його інтерпретувати. Ви можете отримати вичерпний перелік кодів помилок в MSDN на сторінці Системні коди помилок (Windows). Крім того, ви можете подивитися в своїх файлах заголовків системи; Файл з усіма константами коду помилки - winerror.h. (Якщо у вас є офіційний SDK від Microsoft для Windows 8 або новіше, це знаходиться в shared папці з папкою include.)

Нотатки про виклик GetLastError () на інших мовах програмування

.net (C #, VB і т. Д.)

З .net ви не повинні P / Invoke в GetLastError () безпосередньо. Це пов'язано з тим, що час виконання .net зробить інші виклики Windows API одним і тим же потоком за вашою спиною. Наприклад, складальник сміття може викликати VirtualFree () якщо він знайде достатньо пам'яті, яку він більше не використовує, і це може відбутися між вашим призначеним викликом функції і вашим викликом GetLastError ().

Замість цього .net надає Marshal.GetLastWin32Error (). яка буде витягувати останню помилку з останнього виклику P / Invoke, який ви самі зробили. Використовуйте це замість прямого виклику GetLastError ().

(.net, схоже, не заважає вам імпортувати GetLastError () будь-якому випадку, я не впевнений, чому.)

Різні засоби, що надаються Go для виклику DLL-функцій (які знаходяться як в syscall пакета, syscall і в пакеті golang.org/x/sys/windows), повертають три значення: r1. r2 і err. r2 ніколи не використовується; Ви можете використовувати порожній ідентифікатор. r1 - значення, що повертається функції. err є результатом виклику GetLastError () але перетвориться в тип, який реалізує error. тому ви можете передати його викликають функцій для обробки.

Оскільки Go не знає, коли викликати GetLastError () а коли ні, він завжди буде повертати помилку nil. Тому типова ідіома обробки помилок Go

не буде працювати. Замість цього ви повинні перевірити r1 точно так же, як і на C, і використовувати тільки err якщо це вказує, що функція виявила помилку:

Повідомлялося про помилку з додатковою інформацією про відмову і успіху

Деякі виклики API можуть досягти успіху або збій більш ніж одним способом. API зазвичай повертають додаткову інформацію як для успішних викликів, так і для помилок (наприклад, CreateMutex).