Rtl delphi что такое
Chris Bensen
This is my blog about software development, mountain unicycling, Photography, and stuff I find interesting.
Wednesday, December 1, 2010
New Delphi RTL symlink functions
Symbolic links (symlinks) have been around on *nix for some time but only recently introduced to Windows in Vista with CreateSymbolicLink. Windows 2000 had introduced junction points which is half way there by allowing a link to directory, also known as a soft link (if the file moves the link points nowhere) but does not allow a link to a file.
Windows has a few idiosyncrasies that everyone should be made aware of. Here is a link to Microsoft symlink documentation but there are a few key differences between Windows and *nix. Symlinks in *nix are simply a file with a link target. The target file can be either a directory or a file and could actually change. Windows on the other hand has symlinks to files and symlinks to directories. They are different and cannot be interchanged as they can with *nix.
In the Delphi RTL the goal was to do what made the most sense for the developer. In most cases this is treating the symlink as a file but in other cases as a directory. The only real problem comes with POSIX when checking if a DirectoryExists and trying to find out information on the symlink. The following are notes that I made of the changes to the Delphi RTL functions in SysUtils.pas and IOUtils.pas.
IsRelativePath returns a boolean value that indicates whether the specified
path is a relative path.
FileCreateSymLink\TFile.CreateSymLink (new, Windows Vista and above)
FileCreateSymLink creates a symbolic link. The parameter Link is the name of
the symbolic link created and Target is the string contained in the symbolic
link. On Windows the target directory must exist at the time of calling FileCreateSymLink.
FileGetSymLinkTarget\TFile.GetSymLinkTarget (new, Windows Vista and above)
FileGetSymLinkTarget reads the contents of a symbolic link. The result is
returned in the symbolic link record given by SymLinkRec.
Note: The access rights of symlinks are unpredictable over network drives. It is
therefore not recommended to create symlinks over a network drive. To enable
remote access of symlinks under Windows Vista and Windows 7 use the command:
«fsutil behavior set SymlinkEvaluation R2R:1 R2L:1»
FileGetSymLinkTarget\TFile.GetSymLinkTarget (new, Windows Vista and above) overload that takes a string
FileGetSymLinkTarget returns the target of a symbolic link.
FileAge retrieves the date-and-time stamp of the specified file as a
TDateTime. This version supports all valid NTFS date-and-time stamps
and returns a boolean value that indicates whether the specified
file exists. If the specified file is a symlink the function is performed on
the target file. If FollowLink is false then the date-and-time of the
symlink file is returned.
FileExists returns a boolean value that indicates whether the specified
file exists. If the specified file is a symlink the function is performed on
the target file. If FollowLink is false then the symlink file is used
regardless if the link is broken.
case 1: file.txt FollowLink = true returns true
case 2: file.txt FollowLink = false returns true
case 3: [does not exist] FollowLink = true returns false
case 4: [does not exist] FollowLink = false returns false
case 9: dir FollowLink = true returns false
case 10: dir FollowLink = false returns false
symlink to directories
DirectoryExists returns a boolean value that indicates whether the
specified directory exists (and is actually a directory). If the specified
file is a symlink the function is performed on the target file. If FollowLink
is false then the symlink file is used. If the link is broken DirectoryExists
will always return false.
Notes:
On Windows there are directory symlinks and file symlinks. On POSIX a symlink is created
as a file that just happens to point to a directory.
case 1: dir FollowLink = true returns true
case 2: dir FollowLink = false returns true
case 3: [does not exist] FollowLink = true returns false
case 4: [does not exist] FollowLink = false returns false
symlink to directories
FileSetAttr (Windows only)
FileSetAttr sets the file attributes of the file given by FileName to the
value given by Attr. The attribute value is formed by OR-ing the
appropriate faXXXX constants. The return value is zero if the function was
successful. Otherwise the return value is a system error code. If the
specified file is a symlink then the function is performed on the target file.
If FollowLink is false then the symlink file is used.
Note: It is suggested to use TFile.SetAttributes because it is cross platform.
DeleteFile deletes the file given by FileName. The return value is True if
the file was successfully deleted, or False if an error occurred. DeleteFile
can delete a symlinks and symlinks to directories.
RemoveDir deletes an existing empty directory. The return value is
True if the directory was successfully deleted, or False if an error
occurred. If the given directory is a symlink to a directory then the
symlink is deleted. On Windows the link can be broken and the symlink
can still be verified to be a symlink.
FileIsReadOnly tests whether a given file is read-only for the current
process and effective user id. If the file does not exist, the
function returns False. (Check FileExists before calling FileIsReadOnly)
This function is platform portable. If the file specified is a symlink
then the function is performed on the target file.
FileSetReadOnly sets the read only state of a file. The file must
exist and the current effective user id must be the owner of the file.
On Unix systems, FileSetReadOnly attempts to set or remove
all three (user, group, and other) write permissions on the file.
If you want to grant partial permissions (writeable for owner but not
for others), use platform specific functions such as chmod.
The function returns True if the file was successfully modified,
False if there was an error. This function is platform portable. If the
specified file is a symlink then the function is performed on the target
file.
FileSetDate sets the OS date-and-time stamp of the file given by FileName
to the value given by Age. The DateTimeToFileDate function can be used to
convert a TDateTime value to an OS date-and-time stamp. The return value
is zero if the function was successful. Otherwise the return value is a
system error code. If the specified file is a symlink then the function is
performed on the target file. If FollowLink is false then the symlink file
is used.
RenameFile renames the file given by OldName to the name given by NewName.
The return value is True if the file was successfully renamed, or False if
an error occurred. If the file specified is a symlink then the function is
performed on the symlink.
Returns all file times associated with a file. If the specified file is a
symlink then the function is performed on the target file. If FollowLink is
false then the symlink file is used.
TSearchRec = record (updated)
Added TimeStamp property
TSymLinkRec = record (new)
Added FollowLink parameter
Added FollowLink parameter
Added FollowLink parameter
Added FollowLink parameter
Added FollowLink parameter
Returns the TDateTime of the file’s creation time, last access time and last write time.
FileGetDateTimeInfo returns the date-and-time stamp of the specified file
and supports all valid NTFS date-and-time stamps. A boolena value is returned
indicating whether the specified file exists. If the specified file is a
symlink the function is performed on the target file. If FollowLink is false
then the date-and-time of the symlink file is returned.
Used by FileGetDateTimeInfo to return the various date times on demand. It is a public record but only consumable.
4 comments:
CreateSymbolicLink is useless for a lot of Delphi apps since Microsoft decided to require administrator privileges to use it. Inconsistently, creating junction points doesn’t, even though they both use DeviceIoControl(FSCTL_SET_REPARSE_POINT) on the backend.
BTW, was there a reason why FileGetSymLinkTarget only returns the fully qualified target, and doesn’t also include the raw path like readlink returns?
There were a few reasons for returning the fully qualified target rather than exactly what the symlink contains. Basically it can be summed up as usability and consistency. But a more in depth explanation is we found the most common use case would be to fix up the path for the target file if it was a relative path. So we put that logic into FileGetSymLinkTarget to reduce the amount of code developers need to write in most cases. There are also some issues on Windows when providing relative paths in certain cases so sticking with fully qualified paths seemed more reasonable to avoid confusion and consistency between platforms. Plus the raw path on Windows contains the device information which is why ExpandVolumeName is called.
Can you make test, with files that belong to the system (owner SYSTEM)?
@Cobaia, I’m not sure exactly what your question is?
Другие компоненты
Как использовать ChartFX?
with ChartFX do begin
Legend [ 0 ] := ‘Значение переменной A’ ;
Legend [ 1 ] := ‘Значение переменной B’ ;
Legend [ 2 ] := ‘Значение переменной C’ ;
CloseData [COD_VALUES] := 0 ;
Как удалить сегодняшнюю дату из TDateTimePicker?
procedure TForm1.DateTimePicker1DropDown(Sender: TObject);
Style := GetWindowLong(wnd, GWL_STYLE);
SetWindowLong(wnd, GWL_STYLE, Style or MCS_NOTODAY or MCS_NOTODAYCIRCLE);
The calendar will still highlite the current day but the circle and the
today display at the bottom are gone.
Глюк при запуске приложений через ShellListView
Для правки данного глюка необходимо изменить следующую процедуру в исходном коде данного компонента:
Как поставить свой формат в TDateTimePicker?
const fmt: PChar = ‘hh:mm’ ;
Загрузка файлов в THTMLViewer и TFrameBrowser
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Readhtml, FramView, FramBrwz, HtmlView;
TForm1 = class (TForm)
procedure FormCreate(Sender: TObject);
procedure FrameBrowser1GetPostRequest(Sender: TObject; IsGet: Boolean;
const URL, Query: String ; Reload: Boolean; var NewURL: String ;
var DocType: ThtmlFileType; var Stream: TMemoryStream);
procedure FrameBrowser1ImageRequest(Sender: TObject; const SRC: String ;
var Stream: TMemoryStream);
procedure TForm1.FormCreate(Sender: TObject);
procedure TForm1.FrameBrowser1GetPostRequest(Sender: TObject;
IsGet: Boolean; const URL, Query: String ; Reload: Boolean;
var NewURL: String ; var DocType: ThtmlFileType;
var Stream: TMemoryStream);
if AnsiLowerCase(sType) = ‘file://’ then
F := TFileStream.Create(S, fmOpenRead);
procedure TForm1.FrameBrowser1ImageRequest(Sender: TObject;
const SRC: String ; var Stream: TMemoryStream);
Как использовать IP Address Control у себя?
Microsoft ® Internet Explorer представляет элемент управления IP-адрес, новый элемент управления похож на элемент управления редактирования, что позволяет пользователю ввести
числовой адрес в сети Интернет-протокола (IP). Этот формат состоит из четырех трехзначных полей. Каждое поле обрабатывается индивидуально; номера полей основываются на нулях и
перейдите слева направо.
HeaderControl с дополнительной возможностью отображения стрелок
Обычный HeaderControl с дополнительной возможностью отображения стрелок
Что такое фреймы?
. 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% процедур. Подробнее: Фреймы на стеке.
Инструменты пользователя
Инструменты сайта
Боковая панель
Навигация
Загрузки всякие
Связь
Содержание
Нововведения по версиям Delphi
TCustomHint
Все контролы могут использовать свойство CustomHint, которое ссылается на потомка TCustomHint.
В этой статье даны скриншоты новых компонент под XP и Вистой.
Padding and Margin Properties
All VCL controls now have Padding and Margin Properties. These two properties work much like they do in HTML, with Padding describing the length in pixels that a container will place controls within itself. The Margin property describes the number of pixels outside of a control that will be given space.
См. также свойство AlignWithMargins
TDockTabSet
TTaskDialog
The Hello World of a Task Dialog:
Можно вставить проверку на предыдущие версии Windows (XP), которые не поддерживали API TaskDialog:
В противном случае показывать MessageBox.
Custom Buttons Можно добавлять свои кнопки:
Command Links
Нужно выставить флаг tfUseCommandLinks. Также можно покнопочно установить свойство CommandLinkHint
Скрытие технических деталей от пользователя
Свойства ExpandedText и ExpandedButtonCaption позволяют добавить свернутый текст в нижнюю панель диалога:
Если установить флаг tfExpandFooterArea, то текст будет показан в футере. Если установить флаг tfExpandedByDefault, то текст сразу будет показан в развернутом виде.
Custom Icons
Hyperlinks
Можно писать гиперссылки в Text, Footer и ExpandedText
Обработчик клика по ссылке следует написать в событии OnHyperlinkClicked.
Footer
Или использовать флаг tfUseHiconFooter и свойство CustomFooterIcon для кастомной иконки
Checkbox
Radio Buttons
Прогрессбар и callback
Установить флаг tfCallbackTimer и описать событие OnTimer (срабатывает 5 раз в секунду)
TButtonedEdit
TLabeledEdit
TLinkLabel
TCategoryPanelGroup
Появилась в delphi 2009
Как убрать рамку?
Для TCategoryPanel установить protected property BevelOuter в bvNone.
Для TCategoryPanelGroup можно убрать бордюр в процедуре CreateParams следующим образом:
Params.Style := Params.Style and (not WS_BORDER);
TGridPanel
Появилась в Delphi 2006.
TGridPanel implements a grid panel control in which each component is placed within a cell on a grid. With a grid panel, a developer can specify the number of rows and columns on the panel, then each component is placed into the next available cell in the grid, regardless of where it is placed with the mouse.
В зависимости от свойства ExpandStyle будут добавляться новые строки (AddRows) или новые столбцы.
Это могут быть кнопки калькулятора, например.
Можно одну панель вставить в другую (TGridPanel в TGridPanel или TFlowPanel в TGridPanel). Свойства Align, Anchor и Constraint тоже никто не отменял.
The tricky part is setting the percentages. If you have a grid with two columns which are currently set to 50% each, and then set the first column to 25%, you’ll find that the widths for the two columns are actually set to 33.33% and 66.67%, rather than 25% and 75% which is probably what you wanted.
Here’s the problem. When you set the width of the first column to 25%, the TColumnItem object notifies the collection that the item has changed, and the collection then notifies the grid panel that the collection (not a particular item) has changed. At this point the grid panel can see that one column is set to 25% and the other is set to 50% but it doesn’t know which one changed. So how does it arrive at 33.33%? It divides a column’s width by the sum of the percentage for all columns. So for column one this would be 25 / (25+50) = 33.33, and for column two this is 50 / (25+50) = 66.67.
If you keep entering 25% over and over again the end result will eventually approach 25%. This is rather awkward but it does work.
Есть способ попроще:
Аналогично бороться с высотой строк в коллекции RowCollection.
Чтобы отменить центрирование и масштабирование контролов, надо использовать свойство Anchor. Причем свойства контролов Top и Left в инспекторе исчезают.
— все контролы будут масштабироваться при ресайзе:
TFlowPanel
Появилась в Delphi 2006.
TFlowPanel is a TPanel descendent that allows controls placed within it to «flow» together depending on the FlowStyle property. The default value is fsLeftRightTopBottom, meaning controls in the TFlowPanel flow from the upper left to the lower right.
В дизайн-тайм перестаскивание контролов мышкой не работает, можно только вырезать контрол и вставить в самый конец, что довольно муторно, если надо переставить много контролов. Но если присмотреться, то можно увидеть в Инспекторе свойств появлением нового магического свойства ControlIndex у любого контрола, внедрившегося в TFlowPanel. Вот его и надо править для переупорядочивания контролов на панели.
Свойство AutWrap, установленное в false, запрещает многострочное размещение контролов на панели.
TButtonGroup
TCategoryButtons
The control can contain any number of categories, and each category can contain any number of buttons. The categories can be moved at runtime if desired, and individual buttons can be moved or copied between categories as well.
TTabSet
TEdit
Delphi 2005
Wildcard in uses statement allowed
Delphi 2006
FastMM is the default memory manager
final keyword for virtual methods
static methods and properties
strict private/protected visibility keyword
Delphi 2010 и ранее
Константы, переменные и типы внутри класса
Вложенные классы: теперь классы можно объявлять внутри классов, цель избежать конфликта имен.
Exit с параметром
значение должно быть того же типа, что и возвращаемое значение функции.
Class and Record Helpers
Предназначены для добавления новой функциональности в существующий класс (или запись) введением новых методов в класс (запись) без наследования.
Перегрузка операторов
Дженерики
Параметрический полиморфизм. Явление, когда компилятор сам вырабатывает соответствующие варианты кода на основании обобщенного алгоритма
Конкретные реализации алгоритмов можно посмотреть в модуле Generics.Collections, где есть TArray, TList, TStack, TQueue, TDictionary, TObjectList, TObjectQueue, TObjectStack, TObjectDictionary и TEnumerator, способные работать с разными типами данных.
Обобщенные алгоритмы экономят время программиста, сокращая только его код, но для каждого типа (для каждой комбинации типов) всегда генерируется новая версия алгоритма (поэтому размер скомпилированных программ увеличивается).
Записи стали объектами
И теперь имеют свои методы, свойства и конструкторы.
Сравнить две записи на равенство с помощью оператора:
Абстрактные классы
Разрешены полностью абстрактные классы (раньше допускались только конкретные методы), содержащие объявления методов для дальнейшего их перекрытия в потомках.
strict private и strict protected
Строгое private — метод или свойство для класса и невидимое никому, вне класса даже в рамках текущего юнита.
Строгое protected — методы в этой секции будут видимы самому классу и его наследникам.
Пример. Некоторым классам необходимо иметь доступ к закрытым элементам друг друга (например, TCollection — коллекция, TCollectionItem — элемент коллекции).
По этой причине во многих языках существует понятие класса, дружественного (friend) к другому классу (в некоторых языках дружественными могут быть и функции). Дружественный класс будет иметь полный доступ к членам другого класса, даже если они закрыты для прочего стороннего кода.
В Delphi нет специальных языковых конструкций для выделения дружественных классов. Вместо этого здесь используется иной механизм. А именно: любые классы в одном модуле (unit) автоматически считаются дружественными друг к другу и могут обращаться к закрытым элементам друг друга.
Поэтому в примере выше TCollection и TCollectionItem являются дружественными, поскольку расположены в одном модуле
Однако на практике критерий дружественности крайне редко выступает в качестве основного критерия для распределения классов по юнитам. Чаще модуль объединяет логические связанные классы. При этом может получаться, как много не связанных друг с другом (в плане дружественности) классов в одном модуле, так и дружественные классы, разнесённые по разным модулям (если такие классы принадлежат разным логическим компонентам).
Сужение дружественности: strict
Понимая, что не всякий класс в модуле должен быть дружественным к другим классам этого же модуля, разработчики Delphi ввели новое ключевое слово strict, которое в комбинации с private и protected позволяют ограничивать доступ к членам класса для других классов в этом же модуле. Так, к примеру, к элементам класса в strict private не может получить доступа ни один код вне этого же класса, даже если этот код находится в том же модуле. Аналогично, доступ к элементам strict protected будут иметь только наследники этого класса, но не другие классы, даже если они будут находится в том же модуле.
Расширение дружественности: хак
Со второй проблемой (дружественные классы в разных модулях) несколько сложнее. В настоящее время Delphi не предоставляет никаких специальных языковых конструкций для разрешения этого конфликта. Вы не можете объявить классы дружественными друг другу, если они находятся в разных модулях. Поэтому программисту придётся использовать обходные пути.
Первый путь — самый простой и прямолинейный. Он заключается в объявлении пустого класса-наследника в том же модуле, где нужно сделать дружественный класс.
Объявляя класс-наследник (TDummySomeClass), мы делаем доступными ему все protected члены (и не важно, в каком модуле они расположены). А то, что этот класс-заглушка объявлен именно в модуле второго класса (TAnotherClass), сделает эти два класса дружественными, что и даст доступ к закрытому полю protected FItem.
Разумеется, если у вас нет контроля над TSomeClass, то вы не сможете изменить область видимости FItem (изменить private на protected).
Второй вариант разрешения конфликта — использование интерфейсов. Интерфейс (interface) — это набор методов, которые можно произвести с объектом. Иными словами, это как бы «копия» public секции объекта. Интерфейсов может быть много поддержано у одного объекта. Любой внешний код может запросить у объекта любой его сервис, если он знает его «имя» (= GUID).
Таким образом, класс TSomeClass может реализовывать один или несколько интерфейсов, предназначенных для его дружественных классов, расположенных в других модулях. Чтобы подчеркнуть внутреннюю направленность интерфейсов, их можно вынести в отдельный недокументированный модуль. [при чем тут дружественность? методы доступны всем, не только дружественным классам]