Функция 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()
- Обнуляйте переменные (с)

Комментариев нет:
Отправить комментарий