Функция Windows, обнаружив ошибку, через механизм локальной памяти потока сопоставляет соответствующий код ошибки с вызывающим потоком. Это позволяет потокам работать независимо друг от друга, не вмешиваясь в чужие ошибки. Когда функция вернет Вам управление, ее возвращаемое значение будет указывать на то, что произошла какая-то ошибка. Какая именно — Вы узнаете, вызвав функцию GetLastError().
(Дж. Рихтер, "Создание эффективных WIN32-приложений")
И на самом деле, некоторые функции (например OpenProcess/OpenMutex), в случае успешного выполнения, не изменяют код последней ошибки.
Псевдо-код фукнции OpenProcess
function OpenProcess(dwDesiredAccess: DWORD; bInheritHandle: Boolean; dwProcessId: DWORD): THandle; stdcall; var Status: NTSTATUS; hProcess: THandle; begin Status := NtOpenProcess(@hProcess, ...); if not NT_SUCCESS(Status) then // error begin SetLastError(NtStatusToDosError(Status)); Result := 0 end else Result := hProcess end;
Таким образом, если функция успешно выполнила свою работу, LastErrorValue не изменяется, и остается таким же, каким было до вызова функции. Поэтому ниже приведенный код не корректен, т.к. возможна ситуация, когда hProcess <> 0, а GetLastError() возвращает значение, отличное от ERROR_SUCCESS
procedure SomeProcedure(ProcessID: Cardinal;); var hProcess: THandle; LastError: Integer; begin hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or SYNCHRONIZE, False, processID); LastError := GetLastError(); if (hProcess <> 0) and (LastError = ERROR_SUCCESS) then begin ... // Делаем что-то полезное ... end; if (hProcess <> 0) then CloseHandle(hProcess) end;
А вот CreateEvent код последней ошибки изменяет (устанавливает его либо в ERROR_SUCCESS, либо в ERROR_ALREADY_EXISTS).
Псевдо-код фукнции CreateEventW
function CreateEventW(lpEventAttributes: PSecurityAttributes; bManualReset, bInitialState: BOOL; lpName: PWideChar): THandle; stdcall; var Status: NTSTATUS; hEvent: THandle; begin Status = NtCreateEvent(@hEvent, ...); if NT_SUCCESS(Status) then begin if (Status = STATUS_OBJECT_NAME_EXISTS) then SetLastError(ERROR_ALREADY_EXISTS) else SetLastError(ERROR_SUCCESS); Result := hEvent end else begin SetLastError(NtStatusToDosError(Status)); Result := 0 end end;
Мораль:
- Сначала необходимо проверить, что вернула функция, и если это значение свидетельствует об ошибке, тогда можно использовать GetLastError()
- Обнуляйте переменные (с)
Комментариев нет:
Отправить комментарий