Блог GunSmoker-а
. when altering one’s mind becomes as easy as programming a computer, what does it mean to be human.
19 апреля 2009 г.
Настройки проектов в Delphi с точки зрения поиска ошибок
О чём идёт речь
Сначала, давайте посмотрим на них: открываем Project/Options. Нас будут интересовать вкладки Compiling и Linking (в старых версиях Delphi они назывались Compiler и Linker):
Напомним, что при смене любой из опций необходимо сделать полный Build проекту (а не просто Compile).
Что означают эти опции?
Самыми важными настройками являются группа опций «Debug information», «Local Symbols» и «Symbol reference info».
Программа представляет собой набор машинных команд. Текст программы представляет собой текстовый файл. Вопрос: как отладчик узнаёт, когда надо остановиться, если вы поставили бряк на строку в тексте? Где же соответствие между текстовым файлом и набором байт в exe-файле? Вот для такой связи и служит отладочная информация. Это, грубо говоря, набор инструкций типа: «машинные коды с 1056 по 1059 относятся к строке 234 модуля Unit1.pas». Вот с помощью такой информации и работает отладчик. Указанные выше опции отвечают за генерацию отладочной информации для ваших модулей.
Бывают ситуации, когда наличие отладочной информации в файле или (хотя бы) рядом с файлом является необходимым. Например, если вы выполняете удалённую отладку или отладку внешнего процесса. Или если вам нужен читаемый стек вызовов в вашем средстве диагностики исключений.
Подключение отладочной информации к приложению осуществляется несколькими способами: либо это опции проекта (а именно: «Map File», «Debug information» (Linker)/«Include TD32 Debug info» или «Include remote debug symbols»), либо это возможности всевозможных экспертов (типа EurekaLog, JCL или madExcept), которые добавляют отладочную информацию в программу в своём формате.
Хочу заметить, что помимо опций Delphi, в самих экспертах/инструментах также могут быть настройки, влияющие на детальность отладочной информации. Например, обзор таких настроек для EurekaLog мы уже делали в этой статье.
Обычное приложение без механизма диагностики исключений
Общие настройки для любых профилей
«Stack Frames» вообще включать незачем.
Генерацию map-файла выключаем.
Профиль Debug
Включаем «Range checking» и (по вкусу) «Overflow checking».
Профиль Release
Выключаем «Range checking», «Overflow checking», «Include TD32 debug info» и «Include remote debug info».
Приложение с механизмом диагностики исключений (типа EurekaLog, JCL или madExcept)
Общие настройки любых профилей
Все опции отладки («Debug information» (Compiler), «Local symbols», «Reference info») держать включёнными, т. к. в противном случае не будет доступна отладочная информация. Соответственно, ваши информационные механизмы пойдут лесом.
Генерацию map-файла включаем, если об этом не позаботился эксперт (маловероятно).
Профиль Debug
Профиль Release
Включаем «Use Debug DCUs».
Выключаем «Range checking», «Overflow checking», «Include TD32 debug info» и «Include remote debug info».
Примечание: если вы используете мало операций с индексами в своей программе (так что дополнительные проверки не замедлят её), то будет хорошей идеей всегда держать опцию «Range checking» включённой.
Что может пойти не так, если настройки будут заданы неверно?
Ну, во-первых, это невозможность отладки (например, отсутствие информации для удалённого отладчика или выключенная опция «Debug information» (Compiler)), большой размер приложения (например, случайно забыли выключить «Debug information» (Linker)/«Include TD32 debug info»), медленная работа (например, компиляция с отладочным кодом), отсутствие или неполный стек вызовов в средствах диагностики исключений (например, выключили «Debug information» (Compiler)). В очень редких и запущенных случаях переключение опций может сказаться на работоспособности программы (например, установка Stack frames может снизить максимально возможную глубину рекурсии). Ну и недочёты по мелочи.
(**) Например: Button1Click состоит всего из двух инструкций: «call A; ret;». Она очень короткая и не использует аргументы или локальные переменные. Поэтому, очевидно, что ей не нужен стековый фрейм. Когда опция «Stack frames» выключена, то для Button1Click стековый фрейм не создаётся (но он создаётся, если опция «Stack frames» будет включена).
Но, для более сложных процедур стековые фреймы будут генерироваться вне зависимости от установки опции «Stack frames».
Например, тоже очень короткая процедура B всегда имеет фрейм. Причина: использование типа String в ShowMessage. Компилятору нужно вставить неявную строковую переменную и неявный try/finally для её освобождения, поэтому процедуре нужен фрейм.
В реальных приложениях фреймы генерируются для 99% процедур. Подробнее: Фреймы на стеке.
GetLastError — Функция Delphi
Что такое правильное использование GetLastError и FormatMessage в Delphi?
У меня есть проблема с использованием сторонних компонентов в Delphi 2006 (также Delphi 7), в котором я получаю «Неизвестная ошибка» при выполнении вызова функции к этому компоненту. У вас есть пример кода, который использует GetLastError и FormatMessage в Delphi, что позволит мне получить больше информации об ошибке? ТИА
Например, вы можете использовать эту функцию, чтобы отобразить последнюю ошибку:
Если вы хотите поднять исключение с этим сообщением, это еще проще:
В то время как DR правильно, есть проблема с этим подходом: Это не позволяет определить контекст, в котором произошла ошибка. Когда-нибудь видели ошибку «Функция API не удалось.» Whithout быть любой мудрее, какую функцию она была и где она happended?
Вот почему я написал функцию RaiseLastOsErrorEx и Win32CheckEx:
Эрудиты
Получить текст сообщения об ошибке Windows код которой получен функцией GetLastError?
. Данная функция описана в юните
( unit ) Windows и возвращает код последней ошибки, которая возникла в
Windows. Для того что бы не гадать, что именно произошло по коду, его
надо конвертировать в удобочитаемое текстовое
, которая описана в юните ( unit ) SysUtils и возвращает по коду ошибки
ее текст. Получить сообщение об ошибке можно при помощи следующего кода.
Напомню, что функция ShowMessage описана в юните ( unit ) Dialogs.
Еще интересные записи по данной теме
This entry was posted on Среда, Май 26th, 2010 at 14:52 and is filed under Delphi. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
GetLastError function
Retrieves the calling thread’s last-error code value. The last-error code is maintained on a per-thread basis. Multiple threads do not overwrite each other’s last-error code.
Visual Basic:В В Applications should call err. LastDllError instead of GetLastError.
Syntax
Parameters
This function has no parameters.
Return Value
The return value is the calling thread’s last-error code.
The Return Value section of the documentation for each function that sets the last-error code notes the conditions under which the function sets the last-error code. Most functions that set the thread’s last-error code set it when they fail. However, some functions also set the last-error code when they succeed. If the function is not documented to set the last-error code, the value returned by this function is simply the most recent last-error code to have been set; some functions set the last-error code to 0 on success and others do not.
Remarks
Functions executed by the calling thread set this value by calling the SetLastError function. You should call the GetLastError function immediately when a function’s return value indicates that such a call will return useful data. That is because some functions call SetLastError with a zero when they succeed, wiping out the error code set by the most recently failed function.
To obtain an error string for system error codes, use the FormatMessage function. For a complete list of error codes provided by the operating system, see System Error Codes.
The error codes returned by a function are not part of the Windows API specification and can vary by operating system or device driver. For this reason, we cannot provide the complete list of error codes that can be returned by each function. There are also many functions whose documentation does not include even a partial list of error codes that can be returned.
Error codes are 32-bit values (bit 31 is the most significant bit). Bit 29 is reserved for application-defined error codes; no system error code has this bit set. If you are defining an error code for your application, set this bit to one. That indicates that the error code has been defined by an application, and ensures that your error code does not conflict with any error codes defined by the system.
To convert a system error into an HRESULT value, use the HRESULT_FROM_WIN32 macro.
Как получить описание кода, полученного GetLastError?
Как получить описание кода, полученного GetLastError?
Функция RTL SysErrorMessage(GetLastError).
procedure TForm1.Button1Click(Sender: TObject);
Добавить комментарий
Не использовать не нормативную лексику.
Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.
ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!
GetLastError Routine
Unit Edit
Description Edit
It will return the value of the last failed windows API call reported by the OS. Normally after calling this function the error state of the OS will be reset.
GetLastError function is a wrapper function for GetLastError.
Technical Comments Edit
(Known issues / Documentation clarifications / Things to be aware of)
Examples Edit
(Please provide links to articles/source code that show how to use this item.)
See Also Edit
(Please provide links to items specifically related to this item.)
User Comments/Tips Edit
(Please leave your name with your comment.)
Почему GetLastError возвращает 0, когда он вызывается в библиотеке DLL?
Предположим, у меня есть библиотека DLL с этим псевдокодом:
Почему GetLastError функция возвращает 0, когда она используется в библиотеке DLL, как показано выше? Есть ли способ получить последний код ошибки для этого случая?
2 ответа
Ваш звонок GetLastError возвращает 0 потому что есть другие API, вызываемые после того, как CreateFile и ваш код исключения выполняется.
Код ошибки, возвращаемый GetLastError локальной переменной потока и разделяемый всем кодом, выполняющимся в вашем потоке. Таким образом, чтобы получить код ошибки, вам нужно вызвать GetLastError сразу после возврата из сбойной функции.
документация объясняет это следующим образом:
На более высоком уровне реальная проблема с этим кодом заключается в том, что он смешивает модели. Вы пытаетесь создать или открыть файл с одной системой (система VCL TStream), но вы проверяете ошибки, вызванные другой системой (Win32 API).
Единственный способ, которым вы можете положиться на результат Win32 GetLastError, — это если вы сами вызываете функции Win32. Зачем? Потому что это единственный способ убедиться, что между вызовом функции Win32 и вашим вызовом GetLastError нет других вызовов функций Win32. Каждый вызов Win32 API может (пере) установить GetLastError.
Несмотря на то, что VCL находится поверх Win32, существует много возможностей для некоторых других вызовов Win32 API между тем, когда возникает ошибка и когда исключение достигает вашего обработчика. Даже если сегодня все работает хорошо, некоторые будущие изменения в реализации VCL могут легко нарушить счастливое совпадение текущей ситуации.
Лучший способ избежать этого «времени зависания», когда необходимые данные уязвимы для перезаписи, — это получить значение GetLastError как можно ближе к точке сбоя и включить его в свойство объекта исключения VCL. Это практически исключает риск невинного нарушения вашего обработчика исключений и точки сбоя, уничтожающей глобальное состояние GetLastError.
GetLastError — Функция Delphi
uses
Windows, SysUtils;
function GetCursor: Integer;
asm
MOV DX, 3D4h
MOV AL, 0Fh
OUT DX, AL
INC DX
XOR EAX, EAX
IN AL, DX
end;
var
H: THandle;
E: Cardinal;
Msg: PAnsiChar;
begin
H := CreateFile(‘\\\\.\\GIVEIO’, GENERIC_READ, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
E := GetLastError;
if H = INVALID_HANDLE_VALUE then
begin
if FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_ALLOCATE_BUFFER, nil, 0,
LANG_RUSSIAN, Msg, 0, nil) <> 0 then
Writeln (‘ERROR_RESOURCE_LANG_NOT_FOUND’);
Writeln (‘Couldn»t access giveio device’);
Writeln (‘Error ‘, E, ‘: ‘, Msg);
Readln;
Halt;
end;
CloseHandle(H);
Writeln(GetCursor);
Readln;
end.
во-вторых нужно передавать не Msg, а @Msg.
в-третьих функция FormatMessage возвращает количество символов в описании ошибки
А вообще коды ошибок описаны в MSDN и лазить по winnt. h вовсе не к чему.
GetLastError function
Retrieves the calling thread’s last-error code value. The last-error code is maintained on a per-thread basis. Multiple threads do not overwrite each other’s last-error code.
Visual Basic:В В Applications should call err. LastDllError instead of GetLastError.
Syntax
Parameters
This function has no parameters.
Return Value
The return value is the calling thread’s last-error code.
The Return Value section of the documentation for each function that sets the last-error code notes the conditions under which the function sets the last-error code. Most functions that set the thread’s last-error code set it when they fail. However, some functions also set the last-error code when they succeed. If the function is not documented to set the last-error code, the value returned by this function is simply the most recent last-error code to have been set; some functions set the last-error code to 0 on success and others do not.
Remarks
Functions executed by the calling thread set this value by calling the SetLastError function. You should call the GetLastError function immediately when a function’s return value indicates that such a call will return useful data. That is because some functions call SetLastError with a zero when they succeed, wiping out the error code set by the most recently failed function.
To obtain an error string for system error codes, use the FormatMessage function. For a complete list of error codes provided by the operating system, see System Error Codes.
The error codes returned by a function are not part of the Windows API specification and can vary by operating system or device driver. For this reason, we cannot provide the complete list of error codes that can be returned by each function. There are also many functions whose documentation does not include even a partial list of error codes that can be returned.
Error codes are 32-bit values (bit 31 is the most significant bit). Bit 29 is reserved for application-defined error codes; no system error code has this bit set. If you are defining an error code for your application, set this bit to one. That indicates that the error code has been defined by an application, and ensures that your error code does not conflict with any error codes defined by the system.
To convert a system error into an HRESULT value, use the HRESULT_FROM_WIN32 macro.
ASD-SOFT
Программирование. Теория и практика.
WinInet в Delphi. Начало. HTTP запрос.
Здравствуйте уважаемые коллеги!
Библиотека WinInet, или Win32 Internet Extensions, предоставляет набор API функций для работы с протоколами HTTP и FTP. В данном примере я покажу как используя данную библиотеку получить исходный HTML код страницы.
Для работы с API нам понадобиться добавить в раздел USES модуль Winapi. WinInet (или просто WinInet для более поздних версий Delphi).
Для начала опишу функции WinInet, которые понадобятся мне в данном примере:
InternetOpen
Это первая функция WinINet, которая должна вызываться в приложении. Она говорит DLL инициализировать внутренние структуры данных и подготовиться к будущим вызовам приложения. В случае неудачи вернет NIL. Информацию об ошибке можно получить с помощь функции GetLastError.
lpszAgent — Указатель на строку содержащую имя приложения, которое используется как user agent в HTTP протоколе.
dwAccessType — Указывает какой тип доступа использовать из списка значений:
INTERNET_OPEN_TYPE_DIRECT | Прямое подключение. |
INTERNET_OPEN_TYPE_PRECONFIG | Получить настройки подключения из реестра. |
INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY | Получает настройки из реестра и предотвращает использование Microsoft JScript или Internet Setup (INS) файла. |
INTERNET_OPEN_TYPE_PROXY | Доступ через прокси сервер. |
lpszProxy — Указатель на строку содержащую адрес прокси сервера, если dwAccessType указан INTERNET_OPEN_TYPE_PROXY.
lpszProxyBypass — Указатель на строку, которая содержит адреса, которые не нужно передавать через прокси.
dwFlags — Флаг дополнительных опций, который может принимать значение:
INTERNET_FLAG_ASYNC | Выполнять только асинхронные запросы. |
INTERNET_FLAG_FROM_CACHE | Все запросы возвращаются только из кэша. Если запрашиваемого элемента нет в кэше, то возвращается ошибка ERROR_FILE_NOT_FOUND. |
INTERNET_FLAG_OFFLINE | Аналогично INTERNET_FLAG_FROM_CACHE запросы возвращаются из кэша. |
InternetConnect
Функция открывает сессию работы с FTP или HTTP протоколом для указанного сайта. При неудаче возвращает NIL.
hInet — Указатель созданный функцией InternetOpen.
lpszServerName — Указатель на строку содержащую имя сервера, например asd-soft. ru или IP адрес.
nServerPort — Порт сервера. Можно использовать константы:
INTERNET_DEFAULT_FTP_PORT | Порт FTP по умолчанию (21). |
INTERNET_DEFAULT_HTTP_PORT | Порт HTTP по умолчанию (80). |
INTERNET_DEFAULT_HTTPS_PORT | Порт HTTPS по умолчанию (443). |
INTERNET_DEFAULT_SOCKS_PORT | Порт SOCKS по умолчанию (1080). |
INTERNET_INVALID_PORT_NUMBER | Использовать стандартный порт для службы, указанной в dwService. |
lpszUsername — Указатель на строку, которая определяет имя пользователя. Если параметр NIL, то функция использует значение по умолчанию. Для FTP протокола это «anonymous».
lpszPassword — Указатель на строку, которая определяет пароль пользователя.
dwService — Определяет тип сервиса:
INTERNET_SERVICE_FTP | FTP протокол. |
INTERNET_SERVICE_GOPHER | Gopher. |
INTERNET_SERVICE_HTTP | HTTP протокол. |
dwFlags — Опции, специфичные для выбранного сервиса в dwService.
dwContext — Указатель на функцию, которая будет обрабатывать возвращаемые события. Например, при асинхронной работе.
HttpOpenRequest
Подготовка HTTP запроса.
hConnect — Указатель на HTTP сессию, созданную функцией InternetConnect.
lpszVerb — Указатель на строку с типом запроса GET или POST. Если указать NIL, то будет использоваться GET запрос.
lpszObjectName — Указатель на строку, которая содержит объект запроса. Это может быть HTML страница, скрипт или файл.
lpszVersion — Указатель на строку с версией протокола. Если передать NIL, то функция использует HTTP версии 1.1 или 1.0 в зависимости от настроек Internet Explorer.
lpszReferrer — Указатель на строку с адресом предыдущей страницы.
lplpszAcceptTypes — Указатель на строку с типом содержимого. Какие именно значения могут быть переданы описаны в этом документе.
dwFlags — Набор флагов из списка:
INTERNET_FLAG_CACHE_IF_NET_FAIL | Возвращать данные из кэша, если сеть не доступна. |
INTERNET_FLAG_HYPERLINK | Перезагружает данные из сети, если нет Expires time или LastModified time. |
INTERNET_FLAG_IGNORE_CERT_CN_INVALID | Отключает проверку SSL/PCT сертификатов, которые возвращает сервер. |
INTERNET_FLAG_IGNORE_CERT_DATE_INVALID | Отключает проверку SSL/PCT сертификатов на достоверные даты. |
INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | При использовании этого флага WinInet позволяет делать переадресацию с HTTPS на HTTP адреса. |
INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS | При использовании этого флага WinInet позволяет делать переадресацию с HTTP на HTTPS адреса. |
INTERNET_FLAG_KEEP_CONNECTION | Поддерживать соединение с сервером. |
INTERNET_FLAG_NEED_FILE | Указывается в случае, если временный файл должен быть создан при отсутствии в кэше. |
INTERNET_FLAG_NO_AUTH | Не использовать автоматическую аутентификацию. |
INTERNET_FLAG_NO_AUTO_REDIRECT | Не использовать автоматическую переадресацию. |
INTERNET_FLAG_NO_CACHE_WRITE | Не добавляет данные в кэш. |
INTERNET_FLAG_NO_COOKIES | Отключает использование кукисов. |
INTERNET_FLAG_NO_UI | Отключает диалоговое окно cookie. |
INTERNET_FLAG_PRAGMA_NOCACHE | Получать данные с исходного сервера, даже при наличии их в кэше прокси сервера. |
INTERNET_FLAG_RELOAD | Запрашивает загрузку данных с сервера, а не из кэша. |
INTERNET_FLAG_RESYNCHRONIZE | Перезагрузить HTTP ресурсы, если они были изменены с момента последней загрузки. |
INTERNET_FLAG_SECURE | Использовать безопасные SSL/PCT транзакции. Имеет смысл только для HTTP запросов. |
dwContext — Ссылка на ресурсы связанные с этим запросом.
HttpSendRequest
Отправляет HTTP запрос. Возвращает True в случае удачного выполнения запроса.
hRequest — Указатель на запрос подготовленный функцией HttpOpenRequest.
lpszHeaders — Указатель на строку с дополнительными заголовками запроса.
dwHeadersLength — Длинна дополнительных заголовков.
lpOptional — Указатель на буфер, содержащий дополнительные данные. Этот параметр обычно используется при POST и PUT запросах.
dwOptionalLength — Размер передаваемого буфера.
HttpQueryInfo
Запросить информацию связанную с HTTP запросом.
hRequest — Указатель на запрос подготовленный функцией HttpOpenRequest.
dwInfoLevel — Набор флагов, определяющих тип возвращаемой информации. Со списком возможных флагов можно ознакомиться на данной странице. В нашем примере нам понадобится всего два:
HTTP_QUERY_FLAG_NUMBER | Указывает на то, что нужно возвращать число в качестве статуса. |
HTTP_QUERY_STATUS_CODE | Нужно возвращать стату. Список возможных статусов перечислен на этой странице. |
lpvBuffer — Указатель на буфер для возвращаемой информации. Этот параметр не может быть NIL.
lpdwBufferLength — Указатель на переменную, в которую будет записан размер возвращаемого буфера.
lpdwReserved — Указатель на переменную в которой содержится индекс заголовка возвращаемой информации.
InternetQueryDataAvailable
Запрашивает кол-во данных полученных в результате запроса.
hFile — Указатель на запрос подготовленный функцией HttpOpenRequest.
lpdwNumberOfBytesAvailable — Указатель на переменную в которую будет передано кол-во доступных байт.
dwFlags — Параметр не используется и должен быть равным 0.
dwContext — Параметр не используется и должен быть равным 0.
InternetReadFile
Читает данные полученные запросом.
hFile — Указатель на запрос подготовленный функцией HttpOpenRequest.
lpBuffer — Указатель на буфер для чтения данных.
dwNumberOfBytesToRead — Кол-во байт для чтения.
lpdwNumberOfBytesRead — Кол-во прочитанных байт.
InternetCloseHandle
Освобождает указатель созданный функциями InternetOpen, InternetConnect или HttpOpenRequest.
hInet — Указатель.
И последняя функция, которая не относится к API WinInet, но которая нам понадобиться: GetLastError — Возвращает код последней ошибки.
Теперь напишем код, который получит HTML код страницы с адресом https://asd-soft. ru/delphi-wininet-begin-http
Результатом выполнения данного кода будет HTML код страницы в переменной ResponseString.
Функция SysErrorMessage — возвращает текст ошибки по коду из GetLastError.
У кого нибудь есть таблица описания кода ошибкок в Delphi (C++ Builder)?
Вы должны вызвать функцию GetLastError непосредственно тогда, когда величина возвращаемого значения функции указывает, что такой вызов даст вам полезную информацию. Это делается потому, что некоторые функции, когда они завершаются успешно, вызывают функцию SetLastError с нулем, чтобы ликвидировать код ошибки установленный самой последней неудавшейся функцией.
Большинство функций, которые устанавливают последнее значение кода ошибки потока, устанавливает его тогда, когда они завершаются ошибкой; несколько функций устанавливают код ошибки, когда они завершаются успешно. Функция, которая завершилась сбоем, обычно указывается кодом ошибки величины возвращаемого значения типа нуля, ПУСТО (NULL) или — (минус) 1. Некоторые функции вызывают SetLastError при условии успешного завершения; на такие случаи обращается внимание в статьях справочника для каждой функции.
https://www. gunsmoker. ru/2009/04/delphi_19.html
https://studiowb. ru/getlasterror-funkcija-delphi/