Delphi, C++
Главная
Вход
Регистрация
Четверг, 02.05.2024, 11:55Приветствую Вас Гость
Меню сайта

Категории раздела

Привет: Гость

Гость, мы рады вас видеть. Пожалуйста зарегистрируйтесь или авторизуйтесь!
Форма входа

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Друзья

Аниме онлайн Асайт. Сайт для тебя и твоих друзей. Для вашего общения!

Наш опрос
Язык программирования который вы используете
Всего ответов: 283

Мини-чат

Главная » FAQ [ Добавить вопрос ]


Передача параметров в дельфи:

Type
 Ta=array of something;
Var
 a:Ta;

Procedure Proc(a:Ta); - внутри процедуры создаётся копия массива, внутри процедуры работа осуществляется только с копией данных

Procedure Proc(var a:Ta); - внутри процедуры код работает именно с переменной а и её содержимым

Procedure
 Proc(const a:Ta); - внутри процедуры запрещено изменять данные переменной а

Procedure Proc(out a:Ta); - при входе в процедуру массив рассматривается как пустой, но после выполнения процедуры можно получить значения


Автор Vit

Взято с Vingrad.ru http://forum.vingrad.ru

Вариант 1.

В Дельфи есть специальный класс для хранения массивов строк - TStringList - очень рекомендую. Вот как вашу строку превратить в TStringList:

Объявление переменной

var
 t:TStringList;

begin

  t:=TStringList.create; //создаём класс

  t.text:=stringReplace('Ваша строка для разделения'
,' ',#13#10,[rfReplaceAll]);//мы заменяем все пробелы на символы конца строки
//теперь можно убедится что у вас строка разбина на элементы:

  showmessage(t[0
]);
  showmessage(t[1
]);
  showmessage(t[2
]);
  showmessage(t[3
]);
...
//после работы надо уничтожить класс

t.free;

Автор Vit
Взято с Vingrad.ru http://forum.vingrad.ru






Вариант 2. Используем стандартные массивы:


  var a:array of string;//наш массив
      s:string
;//строка которую мы будем разбивать
begin

  s:='Windows Messages SysUtils Variants Classes Graphics Controls Forms'
;
  Repeat
 //мы постепенно заполняем массив на каждом шаге цикла по 1 элементу
    setlength(a,length(a)+1
);//увеличиваем размер массива на 1
    if
 pos(' ',s)>0 then //если есть пробел то надо взять слово до пробела
      begin

        a[length(a)-1
]:=copy(s,1, pos(' ',s));//присвоение последнему элементу массива первого слова
        s:=copy(s,pos(' '
,s)+1, length(s));//удаляем из строки первое слово
      end

    else
//в строке осталось только одно слово
      begin

        a[length(a)-1
]:=s;// присвоим последнее слово
        break;//выход из цикла

      end
;
  Until
 False;//цикл бесконечный, выход изнутри
//теперь проверяем что получили

  showmessage(a[0
]);
  showmessage(a[1
]);
  showmessage(a[2
]);

После использования массива не забудте освободить память a:=nil или setlength(a,0)

Автор Vit
Взято с Vingrad.ru http://forum.vingrad.ru

Может у кого-нибудь есть готовая функция поиска(выборки) слов по маске (с использованием символов '*' и '?').

Такая функция в Дельфи есть: MatchesMask из модуля masks.

Автор ответа: MBo

Взято с Vingrad.ru http://forum.vingrad.ru

Self - это явное задание экземпляра класса в его методе.

Например для твоей формы это указание на саму форму:

procedure
 TForm1.Button1Click(Sender: TObject);
begin

  showmessage(self.classname+#13#10
+self.name);
end
;

Если например это MDI форма то это будет указатель именно на тот экземпляр для которого выполняется этот код. На практике Self обычно применяется при написании своих классов, когда ты пишешь класс или компонент, то у тебя нет переменной с экземпляром этого компонента, следовательно чтобы обратится к экземпляру (который появится только в коде конечного пользователя, который будет использовать компонент) класса нужна переменная - вот она и берётся за self.

Автор ответа: Vit
Взято с Vingrad.ru http://forum.vingrad.ru






Чтобы понять, что такое self надо понять что такое метод класса. Метод класса - это просто функция(процедура) который имеет дополнительный неявный параметр - указатель на экземпляр класса. То есть:

TMy=class
  x:integer;
  procedure
 Proc(val:integer);
end
;

procedure
 TMy.Proc(val:integer);
begin

  x:=val;
end
;

После компиляции это будет практически то же самое, что:

procedure Proc(self:TMy;val:integer);
begin

  self.x:=val;
end
;

То есть на самом деле в методе Proc обращаясь к x мы на самом деле обращаемся к self.x, просто переменная self опускается. В скомпилированном коде нет такого понятия как классы - есть только код и память. Все методы классов превращаются в обыкновенные функции, в которым качестве первого параметра передается указатель на область памяти где лежит созданный пользователем экземпляр класса, который они и используют для чтения или записи(а так же для вызова) того, что мы называем членами класса.

var
  m1,m2:TMy;
begin

  .....
  m1.Proc(4
); // -> Proc(m1,4)
  m2.Proc(4
); // -> Proc(m2,4)
end
;


Автор ответа: Fantasist
Взято с Vingrad.ru http://forum.vingrad.ru

Ошибка "Access Violation" возникает, когда идёт обращение к памяти к которой обращение запрещено. Это возможно во многих случаях, но наиболее типичные ситуации я попытаюсь перечислить:

1) Обращение к не созданному объекту.

var
 e:TEdit;
begin

  e.text:='Hello world!'
;
end
;

В данном случае объект e ещё не создан и идёт обращение к памяти, которая ещё не выделена.


2) Обращение к уже разрушенному объекту:

var e:TEdit;
begin

  ...
  e.free;
  ...
  e.text:='Hello world'
;
end
;

Тут есть хитрость, допустим вы хотите проверить есть ли объект и модернизируете код:

if e<>nil then e.text:='Hello world!';

или

if assigned(e) then  e.text:='Hello world!';

Особенно часто приходится такое делать когда
надо уничтожить объект:

if e<>nil then e.free;

Так вот - такой код может быть источником ошибки, так как метод Free автоматически не устанавливает указатель в Nil. Обязательно после каждого Free используйте установление указателя в nil:

e.free;
e:=nil
;

3) При выходе за границы динамического массива обычно генерится ошибка "Index out of bound", но возможно и возникновение Access Violation, особенно когда не стоят опции компилляции по проверки границ массивов. Эта ошибка может быть очень сложна в отлаживании - дело в том что допустим у вас есть массив а длиной в 10 элементов, в пишете:

a[20]:=smething;

И эта строка может пройти как и надо, без всяких проблем, но её выполнение повредит какой-то другой код, причём каждый раз другой! Теперь самая безобидная операция типа i:=10 может вдруг внезапно дать Access Violation.

3) На форме на onCreate вызывается что-то с других форм - эти другие формы на этот момент еще не созданы

4) На форме на onDestroy вызывается что-то с других форм - эти другие формы на этот момент уже разрушены


Автор Vit
Взято с Vingrad.ru http://forum.vingrad.ru

Как в Run-time сгененрировать строку типа

'{821AB2C7-559D-48E0-A3EE-6DD50E83234C}'


Типа как в среде при нажатии Ctrl-Shift-G. Функция CoCreateGuid выводит значение типа TGUID, я нигде не нашёл функции конвертации TGUID -> String. Может кто знает такую функцию?

Автор ответа:
Vit
Взято с Vingrad.ru http://forum.vingrad.ru





Есть такая функция. Как ни странно называется она GUIDToString, и живет в SysUtils.

Автор ответа:
Fantasist
Взято с Vingrad.ru http://forum.vingrad.ru

Прибавляешь 0.5 затем округляешь:

Uses
 Math;  

Function
 RoundMax(Num:real; prec:integer):real; 
begin
 
result:=roundto(num+Power(10
, prec-1)*5, prec); 
end
;    


До сотых соответственно будет:

Function
 RoundMax100(Num:real):real; 
begin
 
result:=round(num*100
+0.5)/100
end
;    


Автор ответа:
Vit
Взято с Vingrad.ru http://forum.vingrad.ru


Application.ExeName
ParamStr(0)
GetModuleFileName()

Автор ответа: rhf

Взято с Vingrad.ru http://forum.vingrad.ru

Тип String:
по смещению -4 храниться длина строки
по смещению -8 храниться счётчик ссылок на строку (когда он обнуляется строка уничтожается)
Сама строка располагается в памяти как есть - каждая буква занимает 1 байт.
При копировании строки:
s1:=s2 - реального копирования не происходит, увеличивается только счётчик ссылок, но если после этого изменить одну из строк:
s1:=s1+'a'
;
то произойдёт физическое копирование содержимого строк, и теперь s1 и s2 будут показывать на разные адреса памяти.
PChar - длина строки определяется от начала до #0 байта, по сути это чистой воды pointer, так что все действия по отслеживанию распределения памяти лежат на программисте - сами заботьтесь о том чтобы хватило места для распределения памяти и освобождении после использования. Тоже одна буква = 1 байт
Для хранения unicode (т.е. 2х байтовых символов) используйте соответствующие символы с приставкой Wide...
Автор ответа:
Vit



Примечание Fantasist'a:

Это верно только если s1 - локальная переменная, или s1 и s2 - обе не локальные. Если s1 не локальная(глобальная или член класса), а s2 - локальная происходит копирование.

Взято с Vingrad.ru http://forum.vingrad.ru

Пример стандартного присвоения события в run-time:

type

  TForm1 = class
(TForm)
    Button1: TButton;
    procedure
 FormCreate(Sender: TObject);
  private

    procedure
 Click(Sender: TObject);
  end
;

var
  Form1: TForm1;

implementation


procedure
 TForm1.Click(Sender: TObject);
begin

  // do something

end
;

procedure
 TForm1.FormCreate(Sender: TObject);
begin

  button1.OnClick:=Click;
end
;

end
.

Автор ответа:
Vit
Взято с Vingrad.ru http://forum.vingrad.ru




А как сделать чтобы "procedure Click" была не методом класса, а отдельно стоящей функцией?


   procedure Click(Self: TObject; Sender: TObject);
begin

 ...
end
;
var

 evhandler: TNotifyEvent;
 TMethod(evhandler).Code := @Click;
 TMethod(evhandler).Data := nil
;
 Button1.OnClick := evhandler;

Без извращений можно так:

TDummy = class

  class
 procedure Click(Sender: TObject);
end
;
Button1.OnClick := TDummy.Click;

Автор ответа:
Le Taon
Взято с Vingrad.ru http://forum.vingrad.ru




По идее, при вызове OnClick первым параметром будет запихнут указатель на экземпляр того класса который в этом OnClick хранится . Я в низкоуровневой реализации не силен, но кажись, так как параметры в процедурах в Delphi передаются через регистры, то ничего страшного не произойдет.


procedure C(Self:pointer;Sender:TObject);
begin

  TButton(Sender).Caption:='ee'
;
end
;

procedure
 TForm1.FormCreate(Sender: TObject);
begin

  @Button1.OnClick:=@c;
end
;

Self тут у нас будет равен nil, а Sender как раз и получается Sender'ом.

Автор ответа:
Fantasist
Взято с Vingrad.ru http://forum.vingrad.ru

1) Есть Class1, с методом Mtd.
2) Eсть Class2 наследованный от Class1, метод Mtd перезаписан
3) В программе используется переменная типа Class2
Можно ли из программы вызвать Mtd от Class1, Другими словами, можно ли вызвать перезаписанный метод класса-предка?

Способ 1(только для не виртуальных методов)

var

a:class2;
begin

a:=class2.Create;
class1(a).mtd;
....
end
;

Автор ответа: Fantasist
Взято с Vingrad.ru http://forum.vingrad.ru




Способ со статическим приведением годится только для
невиртуальных методов, имеющих одно имя.
Вызов же виртуальных методов от статического типа не зависит.
В твоём простейшем случае достаточно написать inherited Mtd;
(ты его можешь вызвать из любого метода TClass2, не только из Mtd).
Трудности возникнут, когда нужно вызвать метод "дедушки" или "прадедушки" и т.д.
Один из способов, описанных в литературе, - временная замена
VMT объекта на "дедушку" и обратно. Но если у дедушки такого метода не было - будет облом.
Я предпочитаю такой способ:

type
 TProc = procedure
 of object;
procedure
 TClassN.SomeMethod;
var

 Proc: TProc;
begin

 TMethod(Proc).Code := @TClass1.Mtd; // Статический адрес

 TMethod(Proc).Data := Self;
 Proc();
end
;

Автор ответа:
Le Taon
Взято с Vingrad.ru http://forum.vingrad.ru

Может кто объяснит подробнее особенности применения директив вызовов процедур: register, pascal, cdecl, stdcall, safecall. В чём отличия, когда и какие надо применять, какие преимущества и недостатки?

Разница в способе передачи параметров в функцию и возврата параметров из функции.
stdcall - юзается (вроде) а винапях. Передача аргументов справа налево. Стек очищает вызываемая процедура. Возвращает разультат в EAX (помойму)
pascal - юзалось в вин16апи. Передача в аргументов слева направо. Стек очищает вызываемая. В паскале результат возвращался в al, ax или в dx:ax. Как в дельфи - не помню, вероятно а EAX.
register - передача всего через регистры проца. Как именно - зависит от компилера.
cdecl - не помню. Вроде тоде, что и stdcall, только стек чистит вызываюзая процедура

Автор ответа: FdX

Взято с Vingrad.ru http://forum.vingrad.ru




sdecl - вызовы в стиле С (для обращения к длл использующим соглашения о вызовах в стиле С). Параметры в сет с права на лево. Очистка - вызывающей процедурой. Обеспечивают обслуживание переменного числа параметров.

Автор ответа:
Dapo
Взято с Vingrad.ru http://forum.vingrad.ru



Эти директивы скорее относятся к способу(ам) реализации вызовов процедур и передачи (примему от) параметров на конкретном машинном языке при компилляции с языков высокого уровня.
Так, например в DOS СИ использовали свои виды реализаций(обычно называемые C-call), а Паскаль - свой. В win32 также различаются реализации для этих языков, но постепенно происходит заимствование фрагментов реализаций друг у друга и их симбиозы (stdcall).
Если ты пишешь только на одном языке и не подключаешь внешних библиотек, созданных другим компиллятором (в другом формате), то тебе, в принципе, все равно, какая реализация используется - компиллятор сам примет верное решение и согласует вызовы подпрограмм в своем стиле. Исключение, пожалуй, составляет лишь опция "registers" - по смыслу это означает приоритетное использование регистров процессора для передачи(получения) данных процедуре. Как правило, это ускоряет вызов процедуры и возврат из нее: может быть использования для повышения быстродействия. Однако это обычно делают установкой глобального флага проекта в момент создания Файнал Релиз, применяя это сразу ко всем подпрограммам.
Однако если тебе необходимо подключить внешнюю библиотеку (например, написанный на СИ dll, вызывающий в свою очередь апи sql-сервера), то будет необходимо учесть способ передачи параметров именно этой библиотеке.
Или при явном вызове win api из кода также нужно учесть способ их вызова (stdcall)...


Автор ответа:
Chingachguk
Взято с Vingrad.ru http://forum.vingrad.ru





Статья P. Below
http://www.swissdelphicenter.chна
Calling conventions influence two things:
- how parameters are passed to a function/procedure (=routines)
- how the call stack is cleaned up when the call returns
Delphi routines can use the calling conventions pascal (the
Delphi 1 default), register (the default for Delphi 2-5), cdecl
(the default used by C/C++ compilers), stdcall (the default used
by the Windows API). There is a fifth one: safecall, which
is only used in the context of interface methods. A good
explanation for what it entails can be found in issue 51
(Nov. 99) of The Delphi Magazine, i will not go into it
further here. Lets go through the first four in detail, using a
couple of test functions with the same parameter list but
different calling conventions. For clearity we compile with
stack frames on, so each routine will start with the prologue
push ebp
mov ebp, esp
The stack layouts given below are for the mov line. Each test
function is called with the same parameter values so one can
use the CPU windows stack pane to study the resulting stack
layout.

1. Pascal calling convention

Function Test1( i: Integer; b: Boolean; d: Double ): Integer;
Pascal;
Pascal calling convention passes parameters on the stack and
pushes them from left to right in the parameter list. Each
parameter occupies a multiple of 4 bytes. The resulting stack
layout is
ebp + 20 value of i, 4 bytes
ebp + 16 value of b, 4 bytes, only lowbyte significant
ebp + 08 value of d, 8 bytes
ebp + 04 return address, 4 bytes
ebp + 00 old ebp value
The parameters are cleared off the stack by the called function
using a
ret $10
instruction ($10 = 16 is the total size of the parameters on
stack).

2. Register calling convention
Function Test2( i: Integer; b: Boolean; d: Double ): Integer;
Register;
Register calling convention passes parameters in registers
eax, edx, ecx and on the stack and processes them from left to
right in the parameter list. There are rules to decide what
goes into registers and what goes on the stack, as detailed
in the Object Pascal Language guide. The resulting stack layout
is
ebp + 08 value of d, 8 bytes
ebp + 04 return address, 4 bytes
ebp + 00 old ebp value
The value of i is passed in eax, the value of b in edx.
The parameters are cleared off the stack by the called function
using a
ret $8
instruction ($8 = 8 is the total size of the parameters on
stack).

3. cdecl calling convention
Function Test3( i: Integer; b: Boolean; d: Double ): Integer;
cdecl;
Cdecl calling convention passes parameters on the stack and
pushes them from right to left in the parameter list. Each
parameter occupies a multiple of 4 bytes. The resulting stack
layout is
ebp + 16 value of d, 8 bytes
ebp + 12 value of b, 4 bytes, only lowbyte significant
ebp + 08 value of i, 4 bytes
ebp + 04 return address, 4 bytes
ebp + 00 old ebp value
The parameters are cleared off the stack by the calling
function, so the function ends with a
ret 0
and after the call instruction we find a
add esp, $10
instruction ($10 = 16 is the total size of the parameters on
stack).

4. Stdcall calling convention
Function Test4( i: Integer; b: Boolean; d: Double ): Integer;
stdcall;
Sdtcall calling convention passes parameters on the stack and
pushes them from right to left in the parameter list. Each
parameter occupies a multiple of 4 bytes. The resulting stack
layout is
ebp + 16 value of d, 8 bytes
ebp + 12 value of b, 4 bytes, only lowbyte significant
ebp + 08 value of i, 4 bytes
ebp + 04 return address, 4 bytes
ebp + 00 old ebp value
The parameters are cleared off the stack by the called function
using a
ret $10
instruction ($10 = 16 is the total size of the parameters on
stack).
When writing DLLs that are only be meant to be used from Delphi
programs you will usually use the register calling convention,
since it is the most efficient one. But this really ties the
DLL to Delphi, no program compiled in another language (with
the exception of BC++ Builder perhaps) will be able to use the
DLL unless it uses assembler to call the functions, since the
Register calling convention (like MS VC _fastcall) is
compiler-specific.
When writing DLLs that should be usable by other programs
regardless of language you use the stdcall calling convention
for exported routines. Any language that can call Windows API
routines will be able to call routines from such a DLL, as long
as you stay away from Delphi-specific data types, like String,
Boolean, objects, real48.
Pascal calling convention is Win16 heritage, it was the default
for the Win16 API but is no longer used on Win32.
A topic loosely tied to calling conventions is name decoration
for exported names in DLLs. Delphi (5 at least) does not
decorate names, regardless of calling convention used. The name
appears in the exported names table exactly as you cite it in
the exports clause of the DLL, case and all. Case is
significant for exported functions in Win32!
Other compilers may decorate names. Unless told to do otherwise
a C compiler will prefix all cdecl functions with an underbar
and will decorate stdcall functions in the format _name@x,
where x is the total parameter size, e.g. _Test3@16. C++ is
even worse, unless functions are declared as extern "C" it will
export names in a decorated format that encodes parameter size
and type, in a compiler-specific fashion. For routines exported
with Pascal calling convention the names may be all uppercase,
but as said above you will not usually encouter this convention
on Win32.
Due to these naming issues it is often appropriate to sic TDUMP
on an unknown DLL you want to interface to, to figure out the
actual names of the exported functions. These can then be given
in a name clause for the external statement if they are
decorated.

Demo DLL:

library
 DemoDLL;
uses
 Windows;

function
 Test1(i: Integer; b: Boolean; d: Double): Integer; pascal;
begin

Result := Round(i * Ord(b) * d);
end
;

function
 Test2(i: Integer; b: Boolean; d: Double): Integer; register;
begin

Result := Round(i * Ord(b) * d);
end
;

function
 Test3(i: Integer; b: Boolean; d: Double): Integer; cdecl;
begin

Result := Round(i * Ord(b) * d);
end
;

function
 Test4(i: Integer; b: Boolean; d: Double): Integer; stdcall;
begin

Result := Round(i * Ord(b) * d);
end
;

exports

Test1 index
 1,
Test2 index
 2,
Test3 index
 3,
Test4 index
 4;

begin

end
.

// Example call from test project:

implementation

{$R *.DFM}

function
 Test1(i: Integer; b: Boolean; d: Double): Integer;pascalexternal 'DEMODLL.DLL' Index 1;
function
 Test2(i: Integer; b: Boolean; d: Double): Integer;registerexternal 'DEMODLL.DLL' Index 2;
function
 Test3(i: Integer; b: Boolean; d: Double): Integer;cdeclexternal 'DEMODLL.DLL' Index 3;
function
 Test4(i: Integer; b: Boolean; d: Double): Integer;stdcallexternal 'DEMODLL.DLL' Index 4;

procedure
 TForm1.Button1Click(Sender: TObject);
var
 i: Integer;
begin

i := Test1(16
, True, 1.0);
i := Test2(16
, True, 1.0);
i := Test3(16
, True, 1.0);
i := Test4(16
, True, 1.0);
end
;

Set breakpoints on the lines and step into the routines with the
CPU window open to see the stack layout.

Взято с Vingrad.ru http://forum.vingrad.ru

Иногда возникают трудности интерпретации дробных чисел - что есть разделитель точка или запятая?

В Дельфи есть системные переменные:
DECIMALSEPARATOR - десятичный разделитель который принят в системе
THOUSANDSEPARATOR - разделитель тысяч, который принят в системе

Для USA регионального стандарта
DECIMALSEPARATOR будет "."
THOUSANDSEPARATOR будет ","

Для России
DECIMALSEPARATOR будет ","
THOUSANDSEPARATOR будет "." или " " (не помню уже)

Автор Vit
Взято с Vingrad.ru http://forum.vingrad.ru


Вот пример написания класса. Этот класс вычисляет сумму квадратов введенных чисел. Этот класс написан мной только для примера, и я исходил из воображений наглядности, а не оптимальности. Большая часть реализации не только не оптимальна, но и бессмыслена, но показывает бОльшую часть простейших приемов создания класса.

unit
 Unit2;

interface


Uses
 classes, Sysutils;

{Нам нужен процедурный тип для создания собственного события. Собственно - это описание процедуры которая должна будет исполнятся при каких-нибудь обстоятельствах}


Type

TError = procedure
(Sender:TObject; Error: stringof object;

{Описание нашего класса, мы его наследуем от TObject, потому ?то нам практи?ески не нужна
никакия функциональность предков}

Type
 TStatistic=Class(TObject)
private
 {здесь описываются только внутренние переменные и процедуры - "для служебного пользования"}
{Описание полей, т.е. переменных которые работают только внутри класса, "снаружи" они не
доступны.}

FList:TStringList;
FPrecision: byte;
{Тоже переменная - для определения события}

FonError: TError;
{функция - будет использоваться только внутри класса, "снаружи" напрямую не доступна}

function
 GetCount: integer;
public
 {Описанное здесь доступно для пользователя класса}
{Конструктор - метод создания класса, имеет смысл его описывать только если он делает
?то-то специфи?еское - например нам надо будет создать переменную FList. В противном слу?ае
его описание можно опустить - будет работать конструктор родительского класса}

Constructor
 Create;
{Деструктор - метод разрушения класса}

Destructor
 Destroy; override;
{Описание методов - собственно методы мало ?ем отли?аются от процедур}

Procedure
 AddValue(Value:String);
Procedure
 Clear;
Function
 Solve:real;
{Описание свойств. Обратите внимание само свойство не способно хранить никакую информацию, это
только указатель на внутренюю струкруру. Например для хранения свойства Precision используется
переменная FPrecision. А для ?тение свойства Count используется функция GetCount}

Property
 Precision:byte read FPrecision write FPrecision;
Property
 Count:integer read GetCount;
{Описание событий. ?то такое событие? - Это указатель на процедуру. Сам класс реализации этой процедуры
не знает. Классу известно только заголовок процедуры, вы в коде программы будете писать реализацию
процедуры, а класс только в нужный момент передаст ей управление, используя указатель onError}

Property
 onError:TError read FonError write FonError;
end
;

implementation


{ TStatistic }


constructor
 TStatistic.Create;
begin

inherited
{Вна?але надо вызвать конструктор класса-родителя}
FList:=TStringList.create;{создаем структуры нашего класса}

end
;

destructor
 TStatistic.Destroy;
begin

FList.Free;{Разрушаем структуры нашего класса}

inherited
;{в последнюю о?ередь вызываем деструктор клсса-родителя}
end
;

procedure
 TStatistic.AddValue(Value: String);
begin

FList.add(Value); {Примерно так мы реализуем метод}

end
;

procedure
 TStatistic.Clear;
begin

FList.clear;
end
;

function
 TStatistic.GetCount: integer;
begin

Result:=FList.count+1
;
end
;

function
 TStatistic.Solve: real;
var
 i:integer;
begin

result:=0
;
for
 i:=0 to FList.count-1 do
begin

try

result:=result+(Sqr(strtofloat(FList[i])));
except

{интересная конструкция. "on e:exception do" - мы "отлавливаем" ошибку как переменную "e".
Эта переменная имеет о?ень полезное свойство e.message - оно содержит описание ошибки. Далее
следует вызов события. Вна?але мы проверяем использует ли пользователь событие:
"if Assigned(FOnError) then", если использует то вызываем его процедуру: FOnError, с параметрами:
self - зарезервированная переменная - указатель на экземпляр нашего класса, e.message - описание
ошибки}

on e:exception do
 
if
 Assigned(FOnError) then FOnError(Self, e.message);
end
;
end
;
end
;

end
.

Вот пример использования этого класса:

unit
 Unit1;

interface


uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type

TForm1 = class
(TForm)
Button1: TButton;
procedure
 Button1Click(Sender: TObject);
private

procedure
 OnError(Sender:TObject; Error: string);
public

{ Public declarations }

end
;

var

Form1: TForm1;

implementation


uses
 Unit2;

{$R *.DFM}


procedure
 TForm1.Button1Click(Sender: TObject);
  var
 Statistic:TStatistic;
begin

Statistic:=TStatistic.create;
Statistic.onError:=onError;
Statistic.AddValue('123423'
);
Statistic.AddValue('123423'
);
showmessage(floattostr(Statistic.solve));
Statistic.Clear;
Statistic.AddValue('123423'
);
Statistic.AddValue('12ssss3'
);
showmessage(floattostr(Statistic.solve));
Statistic.Free;
end
;

procedure
 TForm1.OnError(Sender: TObject; Error: string);
begin

showmessage('Error inside class:'
+Sender.ClassName+#13#10+Error);
end
;

end
.

Автор ответа: Vit
Взято с Vingrad.ru http://forum.vingrad.ru

unit EditorVMTandDMTTables;

interface


// функция служит для выяснения существования VMT у класса

// возвращает True, если класс имеет VMT и False - если нет

function
 IsVMTExist(Cls: TClass): Boolean;

// процедура служит для замены адреса метода в VMT класса со смещением

// Offset(должно быть кратно 4) новым адресом, хранящимся в NewMet

// примечание: перед вызовом этой процедуры проверяйте существование

// VMT у класса функцией IsVMTExist

procedure
 VirtMethodReplace(Cls: TClass; Offset: LongWord; NewMet: Pointer); overload;

// процедура служит для замены адреса метода, хранящегося в OldMet,

// в VMT класса новым адресом, хранящимся в NewMet

// примечание: перед вызовом этой процедуры проверяйте существование

// VMT у класса функцией IsVMTExist

procedure
 VirtMethodReplace(Cls: TClass; OldMet, NewMet: Pointer); overload;

// функция служит для замены адреса динамического метода класса с индексом,

// хранящимся в Index, новым адресом, хранящимся в NewMet

// возвращает True, если метод с данным индексом найден и False - если нет

function
 DynMethodReplace(Cls: TClass; Index: Word; NewMet: Pointer): Boolean; overload;

// функция служит для замены адреса динамического метода класса, хранящегося

// в OldMet, новым адресом, хранящимся в NewMet

// возвращает True, если метод с данным адресом найден и False - если нет

function
 DynMethodReplace(Cls: TClass; OldMet, NewMet: Pointer): Boolean; overload;

implementation


// функция служит для получения указателя на байт, следующий за адресом

// последнего метода в VMT класса

// возвращает nil в случае, если у класса нет VMT

// функция является "внутренней" в модуле

// (используется другими подпрограммами и не объявлена в секции interface)

// , поэтому используйте её только если

// Вы полностью уверены в своих действиях(она изменяет "рабочие" регистры

// ECX и EDX)

function
 GetVMTEnd(Cls: TClass): Pointer;
asm

        // Вход: Cls --> EAX

        // Выход: Result --> EAX


        PUSH    EBX
        MOV     ECX, 8

        MOV     EBX, -1

        MOV     EDX, vmtSelfPtr
@@cycle:
        ADD     EDX, 4

        CMP     [EAX + EDX], EAX
        JE      @@vmt_not
_found
        JB      @@continue
        CMP     [EAX + EDX], EBX
        JAE     @@continue
        MOV     EBX, [EAX + EDX]
@@continue:
        DEC     ECX
        JNZ     @@cycle
        MOV     EAX, EBX
        JMP     @@exit
@@vmt_not
_found:
        XOR
     EAX, EAX
@@exit:
        POP     EBX

end
;

function
 IsVMTExist(Cls: TClass): Boolean;
asm

        // Вход: Cls --> EAX

        // Выход: Result --> AL


        CALL    GetVMTEnd
        TEST    EAX, EAX
        JZ      @@vmt_not
_found
        MOV     AL, 1

@@vmt_not
_found:

end
;

procedure
 VirtMethodReplace(Cls: TClass; Offset: LongWord; NewMet: Pointer); overload;
asm

        // Вход: Cls --> EAX, Offset --> EDX, NewMet --> ECX

        
        MOV     [EAX + EDX], ECX

end
;

procedure
 VirtMethodReplace(Cls: TClass; OldMet, NewMet: Pointer); overload;
asm

        // Вход: Cls --> EAX, OldMet --> EDX, NewMet --> ECX

       
        PUSH    EDI
        MOV     EDI, EAX
        PUSH    ECX
        PUSH    EDX
        PUSH    EAX
        CALL    GetVMTEnd
        POP     EDX
        SUB     EAX, EDX
        SHR
     EAX, 2
        POP     EDX
        POP     ECX
        PUSH    ECX
        MOV     ECX, EAX
        MOV     EAX, EDX
        POP     EDX
        REPNE   SCASD
        JNE     @@OldMet_not
_found
        MOV     [EDI - 4
], EDX
@@OldMet_not
_found:
        POP     EDI
       
end
;

function
 DynMethodReplace(Cls: TClass; Index: Word; NewMet: Pointer): Boolean; overload;
asm

        // Вход: Cls --> EAX, Index --> DX, NewMet --> ECX

        // Выход: Result --> AL


        PUSH    EDI
        PUSH    ESI
        MOV     ESI, ECX
        XOR
     EAX, EDX
        XOR
     EDX, EAX
        XOR
     EAX, EDX
        JMP     @@start
@@cycle:
        MOV     EDX, [EDX]
@@start:
        MOV     EDI, [EDX].vmtDynamicTable
        TEST    EDI, EDI
        JZ      @@get_parent_dmt
        MOVZX   ECX, WORD PTR [EDI]
        PUSH    ECX
        ADD     EDI, 2

        REPNE   SCASW
        JE      @@Index
_found
        POP     ECX
@@get_parent_dmt:
        MOV     EDX, [EDX].vmtParent
        TEST    EDX, EDX
        JNZ     @@cycle
        JMP     @@Index
_not_found
@@Index
_found:
        POP     EAX
        SHL
     EAX, 1
        SUB     EAX, ECX
        MOV     [EDI + EAX * 2
 - 4], ESI
        MOV     AL, 1

        JMP     @@exit
@@Index
_not_found:
        XOR
     AL, AL
@@exit:
        POP     ESI
        POP     EDI
        
end
;
 
function
 DynMethodReplace(Cls: TClass; OldMet, NewMet: Pointer): Boolean; overload;
asm

        // Вход: Cls --> EAX, OldMet --> EDX, NewMet --> ECX

        // Выход: Result --> AL


        PUSH    EDI
        PUSH    ESI
        MOV     ESI, ECX
        XOR
     EAX, EDX
        XOR
     EDX, EAX
        XOR
     EAX, EDX
        JMP     @@start
@@cycle:
        MOV     EDX, [EDX]
@@start:
        MOV     EDI, [EDX].vmtDynamicTable
        TEST    EDI, EDI
        JZ      @@get_parent_dmt
        MOVZX   ECX, WORD PTR [EDI]
        LEA     EDI, EDI + 2
 * ECX + 2
        REPNE   SCASD
        JE      @@OldMet_found
@@get_parent_dmt:
        MOV     EDX, [EDX].vmtParent
        TEST    EDX, EDX
        JNZ     @@cycle
        JMP     @@OldMet_not
_found
@@OldMet_found:
        MOV     [EDI - 4
], ESI
        MOV     AL, 1

        JMP     @@exit
@@OldMet_not
_found:
        XOR
     AL, AL
@@exit:
        POP     ESI
        POP     EDI

end
;

end
.

Автор ___ALex___ Форум: http://pascal.dax.ru

Взято из FAQ: http://blackman.km.ru/myfaq/cont4.phtml

BEEP , для дельфи , который работает, как в B.Pascal 7.0

Я применяю следующий код, однако он работает только под Win9x/me
(Под WinNT/2000/XP вы можете использовать Beep(Tone, Duration)
- задавать тон и продолжительность звучания).

procedure Sound(Freq : Word);
  var
 B : Byte;
begin
 
if
 Freq > 18 then
begin

Freq := Word(1193181
 div LongInt(Freq));
B := Byte(GetPort($61
)); 
if
 (B and 3) = 0 then
begin

SetPort($61
, Word(B or 3));
SetPort($43
$B6);
end

SetPort($42
, Freq);
SetPort($42
, Freq shr 8);
end
;
end


procedure
 NoSound;
var
 Value: Word;
begin
 
Value := GetPort($61
and $FC;
SetPort($61
, Value);
end


procedure
 SetPort(address, Value:Word);
var
 bValue: byte;
begin
 
bValue := trunc(Value and
 255);
asm

  mov dx, address
  mov al, bValue
  out
 dx, al
end
;
end


function
 GetPort(address:word):word;
var
 bValue: byte;
begin
 
asm

  mov dx, address
  in
 al, dx
  mov bValue, al
end
;
GetPort := bValue;
end
;

Взято с Vingrad.ru http://forum.vingrad.ru

При создании визуальных контролов в runtime, важным моментом является назначение родительских свойств и использование метода SetBounds, чтобы этот контрол стал видимы.


type
 
  TForm1 = class
(TForm) 
  protected
 
    MyLabel: TLabel; 
    procedure
 LabelClick(Sender: TObject); 
    procedure
 CreateControl; 
  end



procedure
 TForm1.LabelClick(Sender: TObject); 
begin
 
  (Sender as
 Label).Caption := ... 
end



procedure
 TForm1.CreateControl; 
var
 
  ALeft, ATop, AWidth, AHeight: Integer; 
begin
 
  ALeft := 10

  ATop := 10

  AWidth := 50

  AHeight := 13

  MyLabel := TLabel.Create(Self); 
  MyLabel.Parent := Self;       
  MyLabel.Name
:='LabelName'
  MyLabel.SetBounds(ALeft, ATop, AWidth, AHeight); 
                                                 
  MyLabel.OnClick := LabelClick; 
end
;

Взято с Исходников.ru http://www.sources.ru/delphi_src1.shtml

Взято из FAQ: http://blackman.km.ru/myfaq/cont4.phtml
Переменная в качестве имени процедуры

Каким образом можно использовать переменную типа String в качестве имени процедуры?
Если все процедуры, которые вы собираетесь вызывать, имеют список с
одними и теми же параметрами (или все без параметров), то это не трудно.
Для этого необходимы: процедурный тип, соответствующий вашей процедуре, например:

type
TMacroProc = procedure
(param: Integer); массив, сопоставляющий имена процедур их адресам во время выполнения приложения: type
TMacroName = string
[32];
TMacroLink = record

name
: TMacroName;
proc: TMacroProc;
end
;
TMacroList = array
 [1..MaxMacroIndex] of TMacroLink; const
Macros: TMacroList = (
(name
'Proc1'; proc: Proc1),
(name
'Proc2'; proc: Proc2),
...
); интерпретатор функций, типа: procedure
 CallMacro(nameString; param: Integer);
var

i: Integer;
begin

for
 i := 1 to MaxMacroIndex do
if
 CompareText(name, Macros[i].name) = 0 then begin
Macros[i].proc(param);
break;
end
;
end
; Макропроцедуры необходимо объявить в секции Interface модуля или с клю?евым словом Far, например: procedure Proc1(n: Integer); far;
begin

...
end
procedure Proc2(n: Integer); far;
begin

...
end


Взято с Vingrad.ru http://forum.vingrad.ru

В Дельфи есть предопределенные переменные языковых установок и форматов:

SysUtils

The following are a set of variables used to define the format for numeric or date/time strings:

var CurrencyString: string;
var CurrencyFormat: Byte;
var NegCurrFormat: Byte;
var ThousandSeparator: Char;
var DecimalSeparator: Char;
var CurrencyDecimals: Byte;
var DateSeparator: Char;
var ShortDateFormat: string;
var LongDateFormat: string;
var TimeSeparator: Char;
var TimeAMString: string;
var TimePMString: string;
var ShortTimeFormat: string;

var LongTimeFormat: string;
var ShortMonthNames: array[1..12] of string;
var LongMonthNames: array[1..12] of string;
var ShortDayNames: array[1..7] of string;
var LongDayNames: array[1..7] of string;

var SysLocale: TSysLocale;
var EraNames: array[1..7] of string;
var EraYearOffsets: array[1..7] of Integer;
var TwoDigitYearCenturyWindow: Word = 50;

var TListSeparator: Char;


Автор ответа: Vit

Взято с Vingrad.ru http://forum.vingrad.ru

procedure SwapVars1(var u, v; Size: Integer); 
var
 
  x: Pointer; 
begin
 
  GetMem(x, Size); 
  try
 
    System.move(u, x^, Size); 
    System.move(v, u, Size); 
    System.move(x^, v, Size); 
  finally
 
    FreeMem(x); 
  end

end



procedure
 SwapVars2(var Source, Dest; Size: Integer); 
  // By Mike Heydon, mheydon@eoh.co.za 

begin
 
  asm
 
     push edi 
     push esi 
     mov esi,Source 
     mov edi,Dest 
     mov ecx,Size 
     cld 
 @1

     mov al,[edi] 
     xchg [esi],al 
     inc si 
     stosb 
     loop @1
 
     pop esi 
     pop edi 
  end

end


procedure
 TForm1.Button2Click(Sender: TObject); 
begin
 
  SwapVars1(X1, X2, SizeOf(Integer)); 
end


Взято с сайта http://www.swissdelphicenter.ch/en/tipsindex.php

Paramcount - показывает сколько параметров передано
Paramstr(0) - это имя с путем твоей программы
Paramstr(1) - имя первого параметра
Paramstr(2) - имя второго параметра и т.д.

Если ты запускаешь:

с:\myprog.exe /a -b22 c:\dev

то Paramcount будет равен 3
Paramstr(0) будет равен с:\myprog.exe
Paramstr(1) будет равен /a
Paramstr(2) будет равен -b22
Paramstr(3) будет равен c:\dev


Параметер это просто строка, набор букв, выполнить ее нельзя - ты можешь только проверить на наличие строки и если она присутствует, то выполнить какое либо действие, это действие ты должен написать сам, никаких стандартных действий нет.

Например у тебя возможно 3 параметра:

Если параметер = "/v" то выдать сообщение, если параметер "/c" то покрасить форму в синий цвет, если параметер "/f" - поменять заголовок формы:

if
 paramstr(1)='/v' then
showmessage('Parameter "/v" was found!'
);
if
 paramstr(1)='/c' then
color:=clBlue;
if
 paramstr(1)='/f' then
caption:='Parameter "/f" was found'
;

Поставь этот код на событие формы onActivate, откомпиллируй и попробуй запустить программу с одним из 3х указанных параметров и ты увидишь что произойдет.

Автор ответа:
Vit
Взято с Vingrad.ru http://forum.vingrad.ru

Автор: Ian Hodger

Основное предназначение этой статьи, заполнить пробелы в оригинальной документации по Borland Delphi Developer, при этом весь программный код, а так же теория, полность совместимы со всеми версиями Delphi.

Основное направление статьи, это познакомиться с использованием ассемблера в Object Pascal. Однако, не будем пропускать и те аспекты программирования, которые будут требовать пояснения для конкретных примеров, приведённых в этой статье.

Использование Ассемблера в Борландовком Delphi
Перед тем, как начать, хотелось бы определиться с уровнем знаний, необходимых для нормального усвоения данного материала. Необходимо быть знакомым со встроенными средствами отладки в Delphi. Так же необходимо иметь представление о таких терминах как тип реализации (instantiation), null pointer и распределение памяти. Если в чём-то из вышеупомянутого Вы сомневаетесь, то постарайтесь быть очень внимательны и осторожны при воплощении данного материала на практике. Кроме того, будет обсуждаться только 32-битный код, так что понадобится компилятор не ниже Delphi 2.0.

Зачем использовать Ассемблер?
На мой взгляд, Object Pascal, это инструмент, позволяющий генерировать быстрый и эффективный код, однако использование ассемблера в некоторых случаях позволяет решать некоторые задачи более эффективно. За всю работу с Delphi, я пришёл к выводу, что использование низкоуровневого кода необходимо в двух случая.

(1) Обработка большого количества данных. Nb. В данный случай не входит ситуация, когда используется язык запроса данных.

(2) В высокоскоростных подпрограммах работы с дисплеем. Nb. Имеется ввиду использование простых процедур на чистом паскале, но никак не внешних библиотек и DirectX.

В конце статьи мы рассмотрим примеры, которые явно отражают значимость этих критериев, а так же не только когда и где использовать ассемблерные вставки, но и как включать такой код в Delphi.

Что такое Ассемблер?
Надеюсь, что Все читатели этой статьи имеют как минимум поверхностное представление о работе процессора. Грубо говоря, это калькулятор с большим объёмом памяти. Память, это не более чем упорядоченная последовательнось двоичных цифр. Каждая такая цифра является байтом. Каждый байт может содержать в себе значение от 0 до 255, а так же имеет свой уникальный адрес, при помощи которого процессор находит нужные значения в памяти. Процессор так же имеет набор регистров (это можно расценить как глобальные переменные). Например eax,ebx,ecx и edx, это универсальные 32-битные регистры. Это значит, что самое большое число, которое мы можем записать в регистр eax, это 2 в степени 32 минус 1, или 4294967295.

Как мы уже выяснили, процессор манипулирует значениями регистров. Машинный код операции прибавления 10 к значению регистра eax будет выглядеть следующим образом
05/0a/00/00/00
Однако, такая запись абсолютно не читабельна и, как следствие, не пригодна при отладке программы. Так вот Ассемблер, это простое представление машинных команд в более удобном виде. Теперь давайте посмотрим, как будет выглядеть прибавление 10 к eax в ассемблерном представлении:
add eax,10 {a := a + 10}
А вот так выглядит вычитаение значения ebx из eax
sub eax,ebx {a := a - b }
Чтобы сохранить значние, можно просто поместить его в другой регистр
mov eax,ecx {a := c }
или даже лучше, сохранить значение по определённому адресу в памяти
mov [1536],eax {сохраняет значение eax по адресу 1536}
и конечно же взять его от туда
mov eax,[1536]

Однако, тут есть важный момент, про который забывать не желательно. Так как регистр 32-битный(4 байта), то его значение будет записано сразу в четыре ячейки памяти 1536, 1537, 1538 и 1539.

А теперь давайте посмотрим, как компилятор преобразует действия с переменными в машинный код. Допустим у нас есть строка
Count := 0;
Для компилятора это означает, что надо просто запомнить значение. Следовательно, компилятор генерирует код, который сохраняет значение в памяти по определённому адресу и следит, чтобы не произошло никаких накладок, и обзывает этот адрес как 'Count'. Вот как выглядит такой код

mov eax,0
 
mov Count,eax 

Компилятор не может использовать строку типа

mov Count,0
из-за того, что как минимум один параметр инструкции должен являться регистром.
Если посмотреть на строку
Count := Count + 1;
то её ассемблерное представление будет выглядеть как
mov eax,Count
add eax,1
mov Count,eax
Для переменных, тип которых отличается от целого, всё усложняется. Однако, рассмотрим эту тему немного позже, а сейчас предлагаю закрепить теорию практическими примерами.

Итак, рассмотрим первый пример. Сразу извинюсь за тривиальность, но с чего-то надо начинать.



function Sum(X,Y:integer):integer; 
begin
 
 Result := X+Y; 
end




А вот так будет выглядеть оперция сложения двух целых чисел на ассемблере:



function Sum(X,Y:integer):integer; 
begin
 
 asm

  mov eax,X
  add eax,Y
  mov Result,eax
 end
;
end
;



Этот код прекрасно работает, однако он не даёт нам преимущества в скорости, а так же потерялось восприятие кода. Но не стоит огорчаться, так как те немногие знания, которые Вы почерпнули из этого материала, можно использовать с большей пользой. Допустим, нам необходимо преобразовать явные значения Red,Green, и Blue в цвета типа TColor, подходящие для использования в Delphi. Тип TColor описан как 24-битный True Colour хранящийся в формате целого числа, то есть четыре байта, старший из которых равен нулю, а далее по порядку красный, зелёный, синий.



function GetColour(Red,Green,Blue:integer):TColor; 
begin
 
 asm

{ecx будет содержать значение TColor}

  mov ecx,0
 
{начинаем с красной компоненты}

  mov eax,Red 
{необходимо убедиться, что красный находится в диапазоне 0<=Red<=255}

  and
 eax,255 
{сдвигаем значение красного в правильное положение}

  shl
 eax,16 
{выравниваем значение TColor}

  xor
 ecx,eax 
{проделываем тоже самое с зелёным}

  mov eax,Green 
  and
 eax,255
  shl
 eax,8
  xor
 ecx,eax
{и тоже самое с синим}

  mov eax,Blue 
  and
 eax,255
  xor
 ecx,eax
  mov Result, ecx
 end
;
end




Заметьте, что я использовал несколько бинарных операций. Эти операции также определены непосредственно в Object Pascal.

Взято с Исходников.ru http://www.sources.ru/delphi_src1.shtml

procedure TForm1.FormCreate(Sender: TObject);
begin

  {This only works for classes registered using RegisterClass}

  RegisterClasses([TButton, TForm]);
end
;


procedure
 TForm1.Button1Click(Sender: TObject);
var

  CRef: TPersistentClass;
  PTI: PTypeInfo;
  AControl: TControl;
begin

  CRef := GetClass('TButton'
);
  if
 CRef <> nil then
  begin

    AControl := TControl(TControlClass(CRef).Create(Self));
    with
 AControl do
    begin

      Parent := Self;
      Width := 50
;
      Height := 30
;
    end
;
    Inc(Id);
  end

  else

    MessageDlg('No such class'
, mtWarning, [mbOk], 0);
end
;


Взято из http://www.lmc-mediaagentur.de/dpool

// Converting method pointers into function pointers 

// Often you need a function pointer for a callback function. But what, if you want to specify a method as 

// an callback? Converting a method pointer to a function pointer is not a trivial task; both types are 

// incomatible with each other. Although you have the possibility to convert like this "@TClass.SomeMethod", 

// this is more a hack than a solution, because it restricts the use of this method to some kind of a class 

// function, where you cannot access instance variables. If you fail to do so, you'll get a wonderful gpf. 

// But there is a better solution: run time code generation! Just allocate an executeable memory block, and 

// write 4 machine code instructions into it: 2 instructions loads the two pointers of the method pointer 

// (code & data) into the registers, one calls the method via the code pointer, and the last is just a return 

// Now you can use this pointer to the allocated memory as a plain funtion pointer, but in fact you are 

// calling a method for a specific instance of a Class. 




type
 TMyMethod = procedure of object


function
 MakeProcInstance(M: TMethod): Pointer; 
begin
 
  // allocate memory 

  GetMem(Result, 15
); 
  asm
 
    // MOV ECX,  

    MOV BYTE PTR [EAX], $B9
 
    MOV ECX, M.Data 
    MOV DWORD PTR [EAX+$1
], ECX 
    // POP EDX 

    MOV BYTE PTR [EAX+$5
], $5A 
    // PUSH ECX 

    MOV BYTE PTR [EAX+$6
], $51 
    // PUSH EDX 

    MOV BYTE PTR [EAX+$7
], $52 
    // MOV ECX,  

    MOV BYTE PTR [EAX+$8
], $B9 
    MOV ECX, M.Code 
    MOV DWORD PTR [EAX+$9
], ECX 
    // JMP ECX 

    MOV BYTE PTR [EAX+$D
], $FF 
    MOV BYTE PTR [EAX+$E
], $E1 
  end

end



procedure
 FreeProcInstance(ProcInstance: Pointer); 
begin
 
  // free memory 

  FreeMem(ProcInstance, 15
); 
end


Взято с сайта http://www.swissdelphicenter.ch/en/tipsindex.php

C Data Type | Object Pascal |  Description 
----------------------------------------------
LPSTR       PAnsiChar;  String >pointer 
LPCSTR      PAnsiChar;  String >pointer 
DWORD       Integer;    Whole numbers 
BOOL        LongBool;   Boolean values 
PBOOL       ^BOOL;      Pointer to a Boolean value 
Pbyte       ^Byte;      Pointer to a byte value 
PINT        ^Integer;   Pointer to an integer value 
Psingle     ^Single;    Pointer to a single (floating point) value 
PWORD       ^Word;      Pointer to a 16-bit value 
PDWORD      ^DWORD;     Pointer to a 32-bit value 
LPDWORD     PDWORD;     Pointer to a 32-bit value 
UCHAR       Byte;       8-bit values (can represent characters) 
PUCHAR      ^Byte;      Pointer to 8-bit values 
SHORT       Smallint;   16-bit whole numbers 
UINT        Integer;    32-bit whole numbers. Traditionally, 
                        this was used to represent unsigned integers, 
                        but Object Pascal does not have a true 
                        unsigned integer data type. 
PUINT       ^UINT;      Pointer to 32-bit whole numbers 
ULONG       Longint;    32-bit whole numbers. Traditionally, 
                        this was used to represent unsigned integers, 
                        but Object Pascal does not have a true 
                        unsigned integer data type. 
PULONG      ^ULONG;     Pointer to 32-bit whole numbers 
PLongint    ^Longint;   Pointer to 32-bit values 
PInteger    ^Integer;   Pointer to 32-bit values 
PSmallInt   ^Smallint;  Pointer to 16-bit values 
PDouble     ^Double;    Pointer to double (floating point) values 
LCID        DWORD;      A local identifier 
LANGID      Word;       A language identifier 
THandle     Integer;    An object handle. Many Windows API functions return a value 
                        of type THandle, which identobject ifies that object within 
                        Windows'internal object tracking tables. 
PHandle     ^THandle;   A pointer to a handle 
WPARAM      Longint;    A 32-bit message parameter. Under earlier versions of Windows, 
                        this was a 16-bit data type. 
LPARAM      Longint;    A 32-bit message parameter 
LRESULT     Longint;    A 32-bit function return value 
HWND        Integer;    A handle to a window. All windowed controls, child windows, 
                        main windows, etc., have a corresponding window handle that 
                        identifies them within Windows'internal tracking tables. 
HHOOK       Integer;    A handle to an installed Windows system hook 
ATOM        Word;       An index into the local or global atom table for a string 
HGLOBAL     THandle;    A handle identifying a globally allocated dynamic memory object. 
                        Under 32-bit Windows, there is no distinction between globally 
                        and locally allocated memory. 
HLOCAL      THandle;    A handle identifying a locally allocated dynamic memory object. 
                        Under 32-bit Windows, there is no distinction between globally 
                        and locally allocated memory. 
FARPROC     Pointer;    A pointer to a procedure, usually used as a parameter type in 
                        functions that require a callback function 
HGDIOBJ     Integer;    A handle to a GDI object. Pens, device contexts, brushes, etc., 
                        all have a handle of this type that identifies them within 
                        Windows'internal tracking tables. 
HBITMAP     Integer;    A handle to a Windows bitmap object 
HBRUSH      Integer;    A handle to a Windows brush object 
HDC         Integer;    A handle to a device context 
HENHMETAFILE  Integer;  A handle to a Windows enhanced metafile object 
HFONT       Integer;    A handle to a Windows logical font object 
HICON       Integer;    A handle to a Windows icon object 
HMENU       Integer;    A handle to a Windows menu object 
HMETAFILE   Integer;    A handle to a Windows metafile object 
HINST       Integer;    A handle to an instance object 
HMODULE     HINST;      A handle to a module 
HPALETTE    Integer;    A handle to a Windows color palette 
HPEN        Integer;    A handle to a Windows pen object 
HRGN        Integer;    A handle to a Windows region object 
HRSRC       Integer;    A handle to a Windows resource object 
HKL         Integer;    A handle to a keyboard layout 
HFILE       Integer;    A handle to an open file 
HCURSOR     HICON;      A handle to a Windows mouse cursor object 
COLORREF    DWORD;      A Windows color reference value, containing values 
                        for the red, green, and of ;bsp;blue components of a color 


Взято с сайта http://www.swissdelphicenter.ch/en/tipsindex.php


type 
  TArrayString = array
 of string

procedure
 DeleteArrayIndex(var X: TArrayString; Index: Integer); 
begin
 
  if
 Index > High(X) then Exit; 
  if
 Index < Low(X) then Exit; 
  if
 Index = High(X) then 
  begin
 
    SetLength(X, Length(X) - 1
); 
    Exit; 
  end

  Finalize(X[Index
]); 
  System.Move(X[Index
 +1], X[Index], 
  (Length(X) - Index
 -1) * SizeOf(string) + 1); 
  SetLength(X, Length(X) - 1
); 
end


// Example : Delete the second item from array a 

// Beispiel : Losche das 2. Element vom array a 


procedure
 TForm1.Button2Click(Sender: TObject); 
var
 
  a: TArrayString; 
begin
 
  DeleteArrayIndex(a, 2
); 
end


Взято с сайта http://www.swissdelphicenter.ch/en/tipsindex.php

You may need to know at runtime what properties are available for a particular component at runtime. The list can be obtained by a call to GetPropList. The types, functions and procedures, including GetPropList, that allow access to this property information reside in the VCL source file TYPINFO.PAS.

GetPropList Parameters



function
 GetPropList(TypeInfo: PTypeInfo; TypeKinds: TTypeKinds; PropList: PPropList): Integer;


The first parameter for GetPropList is of type PTypeInfo, and is part of the RTTI (Run Time Type Information) available for any object. The record structure defined:



PPTypeInfo = ^PTypeInfo;
PTypeInfo = ^TTypeInfo;
TTypeInfo = record

  Kind: TTypeKind;
  Name
: ShortString;
  {TypeData: TTypeData}

end
;


The TTypeInfo record can be accessed through the objects ClassInfo property. For example, if you were getting the property list of a TButton, the call might look, so far, like this:



GetPropList(Button1.ClassInfo, ....


The second parameter, of type TTypeKinds, is a set type that acts as a filter for the kinds of properties to include in the list. There are a number of valid entries that could be included in the set (see TYPEINFO.PAS), but tkProperties covers the majority. Now our call to GetPropList would look like:



GetPropList(Button1.ClassInfo, tkProperties ....


The last parameter, PPropList is an array of PPropInfo and is defined in TYPEINFO.PAS:


PPropList = ^TPropList;
TPropList = array
[0..16379of PPropInfo;


Now the call might read:


procedure TForm1.FormCreate(Sender: TObject);
var

  PropList: PPropList;
begin

  PropList := AllocMem(SizeOf(PropList^));
  GetPropList(TButton.ClassInfo, tkProperties + [tkMethod], PropList);
{...}



Getting Additional Information from the TTypeInfo Record:

The example at the end of this document lists not just the property name, but it's type. The name of the property type resides in an additional set of structures. Let's take a second look at the TPropInfo record. Notice that it contains a PPTypeInfo that points ultimately to a TTypeInfo record. TTypeInfo contains the class name of the property.



PPropInfo = ^TPropInfo;
TPropInfo = packed
 record
  PropType: PPTypeInfo;
  GetProc: Pointer;
  SetProc: Pointer;
  StoredProc: Pointer;
  Index
: Integer;
  Default
: Longint;
  NameIndex: SmallInt;
  Name
: ShortString;
end
;


PPTypeInfo = ^PTypeInfo;
PTypeInfo = ^TTypeInfo;
TTypeInfo = record

  Kind: TTypeKind;
  Name
: ShortString;
  {TypeData: TTypeData}

end
;


The example below shows how to set up the call to GetPropList, and how to access the array elements. TForm will be referenced in this example instead of TButton, but you can substitute other values in the GetPropList call. The visible result will be to fill the list with the property name and type of the TForm properties.

This project requires a TListBox. Enter the code below in the forms OnCreate event handler.



uses
  TypInfo;


procedure
 TForm1.FormCreate(Sender: TObject);
var

  PropList: PPropList;
  i: integer;
begin

  PropList := AllocMem(SizeOf(PropList^));
  i := 0
;
  try

    GetPropList(TForm.ClassInfo, tkProperties + [tkMethod], PropList);
    while
 (PropList^[i] <> Niland (i < High(PropList^)) do
    begin

      ListBox1.Items.Add(PropList^[i].Name
 + ': ' + PropList^[i].PropType^.Name);
      Inc(i);
    end
;
  finally

    FreeMem(PropList);
  end
;
end
;


Взято из http://www.lmc-mediaagentur.de/dpool

function GetProperty(AControl: TPersistent; AProperty: String): PPropInfo;
var

  i: Integer;
  props: PPropList;
  typeData: PTypeData;
begin

  Result := nil
;
  if
 (AControl = nilor (AControl.ClassInfo = nilthen
    Exit;
  typeData := GetTypeData(AControl.ClassInfo);
  if
 (typeData = nilor (typeData^.PropCount = 0then
    Exit;
  GetMem(props, typeData^.PropCount * SizeOf(Pointer));
  try

    GetPropInfos(AControl.ClassInfo, props);
    for
 i := 0 to typeData^.PropCount - 1 do
    begin

      with
 Props^[i]^ do
        if
 (Name = AProperty) then
          result := Props^[i];
    end
;
  finally

    FreeMem(props);
  end
;
end
;


procedure
 TForm1.Button1Click(Sender: TObject);
var

  propInfo: PPropInfo;
begin

  PropInfo := GetProperty(Button1.Font, 'Name'
);
  if
 PropInfo <> nil then
    SetStrProp(Button1.Font, PropInfo, 'Arial'
);
end
;

Взято из http://www.lmc-mediaagentur.de/dpool

You can use RTTI to do this. Here is how to change a particular component:

procedure
 TForm1.BtnClick(Sender: TObject);
var

  p: PPropInfo;
  f: TFont;
begin

  f := TFont.Create;
  {Setup the font properties}

  f.Name
 := 'Arial';
  p := GetPropInfo(Sender.ClassInfo, 'Font'
);
  if
 Assigned(p) then
    SetOrdProp(Sender, p, Integer(f));
  f.Free;
end
;


To get at all the forms loop through the Screen global variable. For each form loop through its Components list calling the above procedure (or something close). If you only create your components at design time that is it. If you create some at runtime and the owner is not the form, then for each component loop through its Components list recursively to get at all the owned components.



Tip by Jeff Overcash



Взято из http://www.lmc-mediaagentur.de/dpool

unit PropertyList;

interface


uses

  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons;

type

  TMyStream = class
(TFileStream)
  private

  FFred: integer;
  published

  property
 Fred: integer read FFred write FFred;
  end
;
type

  TFrmPropertyList = class
(TForm)
  SpeedButton1: TSpeedButton;
  ListBox1: TListBox;
  procedure
 SpeedButton1Click(Sender: TObject);
private

  { Private declarations }

public

  { Public declarations }

end
;

var

  FrmPropertyList: TFrmPropertyList;

implementation


{$R *.DFM}


uses

  TypInfo;

procedure
 ListProperties(AInstance: TPersistent; AList: TStrings);
var

  i: integer;
  pInfo: PTypeInfo;
  pType: PTypeData;
  propList: PPropList;
  propCnt: integer;
  tmpStr: string
;
begin

  pInfo := AInstance.ClassInfo;
  if
 (pInfo = nilor (pInfo^.Kind <> tkClass) then
    raise
 Exception.Create('Invalid type information');
  pType := GetTypeData(pInfo);  {Pointer to TTypeData}

  AList.Add('Class name: '
 + pInfo^.Name);
  {If any properties, add them to the list}

  propCnt := pType^.PropCount;
  if
 propCnt > 0 then 
  begin

    AList.Add (EmptyStr);
    tmpStr := IntToStr(propCnt) + ' Propert'
;
    if
 propCnt > 1 then
      tmpStr := tmpStr + 'ies'

    else

      tmpStr := tmpStr + 'y'
;
    AList.Add(tmpStr);
    FillChar(tmpStr[1
], Length(tmpStr), '-');
    AList.Add(tmpStr);
    {Get memory for the property list}

    GetMem(propList, sizeOf(PPropInfo) * propCnt);
    try

      {Fill in the property list}

      GetPropInfos(pInfo, propList);
      {Fill in info for each property}

      for
 i := 0 to propCnt - 1 do
        AList.Add(propList[i].Name
 + ': ' + propList[i].PropType^.Name);
    finally

      FreeMem(propList, sizeOf(PPropInfo) * propCnt);
    end
;
  end
;
end
;


function
 GetPropertyList(AControl: TPersistent; AProperty: string): PPropInfo;
var

  i: integer;
  props: PPropList;
  typeData: PTypeData;
begin

  Result := nil
;
  if
 (AControl = nilor (AControl.ClassInfo = nilthen
    Exit;
  typeData := GetTypeData(AControl.ClassInfo);
  if
 (typeData = nilor (typeData^.PropCount = 0then
    Exit;
  GetMem(props, typeData^.PropCount * SizeOf(Pointer));
  try

    GetPropInfos(AControl.ClassInfo, props);
    for
 i := 0 to typeData^.PropCount - 1 do
    begin

      with
 Props^[i]^ do
        if
 (Name = AProperty) then
          result := Props^[i];
    end
;
  finally

    FreeMem(props);
  end
;
end
;


procedure
 TFrmPropertyList.SpeedButton1Click(Sender: TObject);
var

  c: integer;
begin

  ListProperties(self, ListBox1.Items);
  for
 c := 0 to ComponentCount - 1 do
  begin

    ListBox1.Items.Add(EmptyStr);
    ListProperties(Components[c], ListBox1.Items);
  end
;
end
;

end
.




Tip by Ralph Friedman


Взято из http://www.lmc-mediaagentur.de/dpool

unit MorePropInfo;

interface


uses

  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type

  TFrmMorePropInfo = class
(TForm)
    Button1: TButton;
    Button2: TButton;
    ListBox1: TListBox;
    procedure
 Button2Click(Sender: TObject);
  private

    { Private declarations }

  public

    { Public declarations }

  end
;

var

  FrmMorePropInfo: TFrmMorePropInfo;

implementation


{$R *.DFM}


uses

  TypInfo;

procedure
 GetPropertyValues(AObj: TObject; AValues: TStrings);
var

  count: integer;
  data: PTypeData;
  default
string;
  i: integer;
  info: PTypeInfo;
  propList: PPropList;
  propInfo: PPropInfo;
  propName: string
;
  value: variant;
begin

  info := AObj.ClassInfo;
  data := GetTypeData(info);
  GetMem(propList, data^.PropCount * SizeOf(PPropInfo));
  try

    count := GetPropList(info, tkAny,  propList);
    for
 i := 0 to count - 1 do
    begin

      propName := propList^[i]^.Name
;
      propInfo := GetPropInfo(info, propName);
      if
 propInfo <> nil then
      begin

        case
 propInfo^.PropType^.Kind of
          tkClass, tkMethod:
            value := '$'
 + IntToHex(GetOrdProp(AObj, propInfo), 8);
          tkFloat:
            value := GetFloatProp(AObj, propInfo);
          tkInteger:
            value := GetOrdProp(AObj, propInfo);
          tkString, tkLString, tkWString:
            value := GetStrProp(AObj, propInfo);
          tkEnumeration:
            value := GetEnumProp(AObj, propInfo);
          else

            value := '???'
;
        end
;
        if
 propInfo.default = longint($80000000then
          default
 := 'none'
        else

          default
 := IntToStr(propInfo.default);
        AValues.Add(Format('%s: %s [default: %s]'
, [propName, value, default]));
        {$80000000 apparently indicates "no default"}

      end
;
    end
;
  finally

    FreeMem(propList, data^.PropCount * SizeOf(PPropInfo));
  end
;
end
;


procedure
 TFrmMorePropInfo.Button2Click(Sender: TObject);
var

  count: integer;
  data: PTypeData;
  i: integer;
  info: PTypeInfo;
  propList: PPropList;
  propInfo: PPropInfo;
  propName: string
;
  propVal: variant;
  tmpS: string
;
begin

  info := Button2.ClassInfo;
  data := GetTypeData(info);
  GetMem(propList, data^.PropCount * SizeOf(PPropInfo));
  try

    count := GetPropList(info, tkAny,  propList);
    ListBox1.Clear;
    for
 i := 0 to count - 1 do
    begin

      propName := propList^[i]^.Name
;
      propInfo := GetPropInfo(info, propName);
      if
 propInfo <> nil then
      begin

        case
 propInfo^.PropType^.Kind of
          tkClass, tkMethod:
            propVal := '$'
 + IntToHex(GetOrdProp(Button2, propInfo), 8);
          tkFloat:
            propVal := GetFloatProp(Button2, propInfo);
          tkInteger:
            propVal := GetOrdProp(Button2, propInfo);
          tkString, tkLString, tkWString:
            propVal := GetStrProp(Button2, propInfo);
          tkEnumeration:
            propVal := GetEnumProp(Button2, propInfo);
          else

            propVal := '...'
;
        end
;
        tmpS := propVal;
        ListBox1.Items.Add(Format('%s: %s [default: %s]'
, [propName, tmpS, '$'
                                             + IntToHex(propInfo.default
8)]));
        {$80000000 apparently indicates "no default"}

      end
;
    end
;
  finally

    FreeMem(propList, data^.PropCount * SizeOf(PPropInfo));
  end
;
end
;

end
.



Tip by Ralph Friedman


Взято из http://www.lmc-mediaagentur.de/dpool

procedure EnumMethods( aClass: TClass; lines: TStrings );
  
  type

    TMethodtableEntry = packed
 Record
      len: Word;
      adr: Pointer;
      name
: ShortString;
  end
;
  {Note: name occupies only the size required, so it is not a true shortstring! The actual
  entry size is variable, so the method table is not an array of TMethodTableEntry!}


var

  pp: ^Pointer;
  pMethodTable: Pointer;
  pMethodEntry: ^TMethodTableEntry;
  i, numEntries: Word;
begin

  if
 aClass = nil then
    Exit;
  pp := Pointer(Integer( aClass ) + vmtMethodtable);
  pMethodTable := pp^;
  lines.Add(format('Class %s: method table at %p'
, [aClass.Classname, pMethodTable ] ));
  if
 pMethodtable <> nil then
  begin

    {first word of the method table contains the number of entries}

    numEntries := PWord( pMethodTable )^;
    lines.Add(format('  %d published methods'
, [numEntries] ));
    {make pointer to first method entry, it starts at the second word of the table}

    pMethodEntry := Pointer(Integer( pMethodTable ) + 2
);
    for
 i := 1 to numEntries do
    begin

      with
 pMethodEntry^ do
        lines.Add(format( '  %d: len: %d, adr: %p, name: %s'
, [i, len, adr, name] ));
      {make pointer to next method entry}

      pMethodEntry := Pointer(Integer( pMethodEntry ) + pMethodEntry^.len);
    end
;
  end
;
    EnumMethods( aClass.ClassParent, lines );
end
;


procedure
 TForm2.Button1Click(Sender: TObject);
begin

  memo1.clear;
  EnumMethods( Classtype, memo1.lines );
end
;

Взято из http://www.lmc-mediaagentur.de/dpool

function GetComponentProperties(Instance: TPersistent; AList: TStrings): Integer;
var

  I, Count: Integer;
  PropInfo: PPropInfo;
  PropList: PPropList;
begin

  Result := 0
;
  Count := GetTypeData(Instance.ClassInfo)^.PropCount;
  if
 Count > 0 then
  begin

    GetMem(PropList, Count * SizeOf(Pointer));
    try

      GetPropInfos(Instance.ClassInfo, PropList);
      for
 I := 0 to Count - 1 do
      begin

        PropInfo := PropList^[I];
        if
 PropInfo = nil then
          Break;
        if
 IsStoredProp(Instance, PropInfo) then
        begin

          {
          case PropInfo^.PropType^.Kind of
            tkInteger:
            tkMethod:
            tkClass:
            ...
          end;
          }

        end
;
        Result := AList.Add(PropInfo^.Name
);
      end
;
    finally

      FreeMem(PropList, Count * SizeOf(Pointer));
    end
;
  end
;
end
;

Tip by Grega Loboda


uses
  TypInfo

procedure
 ListProperties(AInstance: TPersistent; AList: TStrings);
var

  i: integer;
  pInfo: PTypeInfo;
  pType: PTypeData;
  propList: PPropList;
  propCnt: integer;
  tmpStr: string
;
begin

  pInfo := AInstance.ClassInfo;
  if
 (pInfo = nilor (pInfo^.Kind <> tkClass) then
    raise
 Exception.Create('Invalid type information');
  pType := GetTypeData(pInfo);  {Pointer to TTypeData}

  AList.Add('Class name: '
 + pInfo^.Name);
  {If any properties, add them to the list}

  propCnt := pType^.PropCount;
  if
 propCnt > 0 then
  begin

    AList.Add(EmptyStr);
    tmpStr := IntToStr(propCnt) + ' Propert'
;
    if
 propCnt > 1 then
      tmpStr := tmpStr + 'ies'

    else

      tmpStr := tmpStr + 'y'
;
    AList.Add(tmpStr);
    FillChar(tmpStr[1
], Length(tmpStr), '-');
    AList.Add(tmpStr);
    {Get memory for the property list}

    GetMem(propList, sizeOf(PPropInfo) * propCnt);
    try

      {Fill in the property list}

      GetPropInfos(pInfo, propList);
      {Fill in info for each property}

      for
 i := 0 to propCnt - 1 do
        AList.Add(propList[i].Name
+': '+propList[i].PropType^.Name);
    finally

      FreeMem(propList, sizeOf(PPropInfo) * propCnt);
    end
;
  end
;
end
;


function
 GetPropertyList(AControl: TPersistent; AProperty: string): PPropInfo;
var

  i: integer;
  props: PPropList;
  typeData: PTypeData;
begin

  Result := nil
;
  if
 (AControl = nilor (AControl.ClassInfo = nilthen
    Exit;
  typeData := GetTypeData(AControl.ClassInfo);
  if
 (typeData = nilor (typeData^.PropCount = 0then
    Exit;
  GetMem(props, typeData^.PropCount * SizeOf(Pointer));
  try

    GetPropInfos(AControl.ClassInfo, props);
    for
 i := 0 to typeData^.PropCount - 1 do
    begin

      with
 Props^[i]^ do
        if
 (Name = AProperty) then
          result := Props^[i];
    end
;
  finally

    FreeMem(props);
  end
;
end
;


And calling this code by:


ListProperties(TProject(treeview1.items[0].data), memo3.lines);


My tProject is defined as


type
   TProject = class
(tComponent)
   private

     FNaam: string
;
     procedure
 SetNaam(const Value: string);
   public

     constructor
 Create(AOwner: tComponent);
     destructor
 Destroy;
   published

     property
 Naam: string read FNaam write SetNaam;
   end
;


Also note the output, there seem to be 2 standard properties (Name and Tag) !

Memo3
Class name: TProject

3 Properties
-------------------
Name: TComponentName
Tag: Integer
Naam: String



Tip by Ronan van Riet

Взято из http://www.lmc-mediaagentur.de/dpool

function hasprop(comp: TComponent; const prop: String): Boolean;
var

  proplist: PPropList;
  numprops, i: Integer;
begin

  result := false;
  getmem(proplist, getTypeData(comp.classinfo)^.propcount * Sizeof(Pointer));
  try

    NumProps := getproplist(comp.classInfo, tkProperties, proplist);
    for
 i := 0 to pred (NumProps) do
    begin

      if
 comparetext(proplist[i]^.Name, prop) = 0 then
      begin

        result := true;
        break;
      end
;
    end
;
  finally

    freemem(proplist, getTypeData(comp.classinfo)^.propcount * Sizeof(Pointer));
  end
;
end
;


procedure
 setcomppropstring(comp: TComponent; const prop, s: String);
var

  proplist: PPropList;
  numprops, i: Integer;
begin

  getmem(proplist, getTypeData(comp.classinfo)^.propcount * Sizeof(Pointer));
  try

    NumProps := getproplist(comp.classInfo, tkProperties, proplist);
    for
 i := 0 to pred (NumProps) do
    begin

      if
 (comparetext(proplist[i]^.Name, prop) = 0and
         (comparetext(proplist[i]^.proptype^.name
'string') = 0 then
      begin

        setStrProp(comp, proplist[i], s);
        break;
      end
;
    end
;
  finally

    freemem(proplist, getTypeData(comp.classinfo)^.propcount * Sizeof(Pointer));
  end
;
end
;


Взято из http://www.lmc-mediaagentur.de/dpool


If I am given a TPersistent object, and a method name, is there a way to determine if the name is an event of TNotifyEvent type? For example, given a TPersistent lMyObj and an event name, "OnDataChanged", how can I determine if OnDataChanged is a TNotifyEvent?


function
 IsNotifyEvent(Sender: TObject; const Event: string): Boolean;
var

  PropInfo: PPropInfo;
  Method: TNotifyEvent;
begin

  Result := False;
  PropInfo := GetPropInfo(Sender.ClassInfo, Event);
  if
 not Assigned(PropInfo) then
    Exit;
  if
 PropInfo.PropType^.Kind <> tkMethod then
    Exit;
  Method := TNotifyEvent(GetMethodProp(Sender, PropInfo));
  Result := Assigned(Method);
end
;



Tip by Jack Sudarev


Взято из http://www.lmc-mediaagentur.de/dpool

function GetFontProp( anObj: TObject): TFont;
var

  PInfo: PPropInfo;
begin

  {Try to get a pointer to the property information for a property with the name 'Font'.
  TObject.ClassInfo returns a pointer to the RTTI table, which we need to pass to GetPropInfo}

  PInfo := GetPropInfo( anObj.ClassInfo, 'font'
 );
  Result := Nil
;
  if
 PInfo <> Nil then
    {found a property with this name, check if it has the correct type}

    if
 (PInfo^.Proptype^.Kind = tkClass) and
       GetTypeData(PInfo^.Proptype^)^.ClassType.InheritsFrom(TFont)
    then
 
      Result := TFont(GetOrdProp( anObj, PInfo ));
end
;

Tip by Peter Below

Взято из http://www.lmc-mediaagentur.de/dpool

Does anyone know if there is an easy way to load the value of a component's property directly from its resource without creating the component? Something like:

if
 ReadPropertyValue('Form1.Button1''width') > 1000 then
ShowMessage('You are about to create a big button!'
);
function
 TForm1.ReadProp(r: TReader): string;
begin

  result := ''
;
  {Determine the value type of the property, read it with the appropriate method of TReader
  and convert it to string. Not all value types are implemented here but you get the idea.}

  case
 r.NextValue of
    vaInt8, vaInt16, vaInt32:
      result := IntToStr(r.ReadInteger);
    vaExtended:
      result := FloatToStr(r.ReadFloat);
    vaString:
      result := r.ReadString;
    else

      r.SkipValue;  {Not implemented}

  end
;
end
;


procedure
 TForm1.ReadRes(PropPath: string; r: TReader);
var

  p: string
;
begin

  {Skip the class name}

  r.ReadStr;
  {Construct the property path}

  if
 PropPath = '' then
    p := r.ReadStr
  else

    p := PropPath + '.'
 + r.ReadStr;
  {Read all properties and its values and fill them into the memo}

  while
 not r.EndOfList do
    Memo1.Lines.Add(p + '.'
 + r.ReadStr + ' = ' + ReadProp(r));
  {Skip over the end of the list of the properties of this component}

  r.CheckValue(vaNull);
  {Recursively read the properties of all sub-components}

  while
 not r.EndOfList do
  begin

    ReadRes(p, r);
    r.CheckValue(vaNull);
  end
;
end
;


procedure
 TForm1.Button1Click(Sender: TObject);
var

  strm: TResourceStream;
  Reader: TReader;
begin

  strm := TResourceStream.Create(HInstance, 'TForm1'
, RT_RCDATA);
  Reader := TReader.Create(strm, 1024
);
  try

    Memo1.Clear;
    Reader.ReadSignature;
    ReadRes(''
, Reader);
  finally

    Reader.Free;
    strm.Free;
  end
;
end
;


Only one small problem.
r.SkipValue was protected (in D5) but I hacked that out with the following code:



type THackReader = class(TReader);
{ ... }
  THackReader(r).SkipValue;


And now it works like a charm.




Tip by Michael Duerig and Tjipke A. van der Plaats




Взято из http://www.lmc-mediaagentur.de/dpool

I am building a routine that checks our forms for validity before deploying them. I would like to use some kind of structure that tests if a component type has access to a certain property, something like: " if (self.Controls[b] has Tag) then ...". Can anyone offer suggestions?
Here's an example of setting a string property for a component if it exists and another for an integer property:

procedure
 SetStringPropertyIfExists(AComp: TComponent; APropName: String;
AValue: String
);
var

  PropInfo: PPropInfo;
  TK: TTypeKind;
begin

  PropInfo := GetPropInfo(AComp.ClassInfo, APropName);
  if
 PropInfo <> nil then
  begin

    TK := PropInfo^.PropType^.Kind;
    if
 (TK = tkString) or (TK = tkLString) or (TK = tkWString) then
      SetStrProp(AComp, PropInfo, AValue);
  end
;
end
;


procedure
 SetIntegerPropertyIfExists(AComp: TComponent; APropName: String;
AValue: Integer);
var

  PropInfo: PPropInfo;
begin

  PropInfo := GetPropInfo(AComp.ClassInfo, APropName);
  if
 PropInfo <> nil then
  begin

    if
 PropInfo^.PropType^.Kind = tkInteger then
      SetOrdProp(AComp, PropInfo, AValue);
  end
;
end
;




Tip by Xavier Pacheco



Взято из http://www.lmc-mediaagentur.de/dpool

How can I assign all property values (or if it's not possible only published property values, or some of them) of one class (TComponent) to another instance of the same class? What I want to do is:

MyComponent1.{property1}
 := MyComponent2.{property1};
{...}

MyComponent2.{propertyN}
 := MyComponent2.{propertyN};

Is there a better and shorter way to do this? I tried this: MyComponent1 := MyComponent2; But it doesn't work. Why not? Can I point to the second component ?


Answer 1:

MyComponent2 and MyComponent1 are pointers to your components, and this kind of assigment leads to MyComponent1 pointing to MyComponent2. But it will not copy its property values.

A better way is to override the assign method of your control, do all property assignment there and call it when you need to copy component attributes. Here's example:



procedure TMyComponent.Assign(Source: TPersistent);
begin

  if
 Source is TMyComponent then
  begin

    property1 := TMyComponent(Source).property1;
    { ... }

  end

  else

    inherited
 Assign(Source);
end
;


To assign properties you'll need to set this line in the code:


MyComponent1.Assign(MyComponent2);



Tip by Serge Gubenko




Answer 2:



procedure EqualClassProperties(AClass1, AClass2: TObject);
var

  PropList: PPropList;
  ClassTypeInfo: PTypeInfo;
  ClassTypeData: PTypeData;
  i: integer;
  NumProps: Integer;
  APersistent : TPersistent;
begin

  if
 AClass1.ClassInfo <> AClass2.ClassInfo then
    exit;
  ClassTypeInfo := AClass1.ClassInfo;
  ClassTypeData := GetTypeData(ClassTypeInfo);
  if
 ClassTypeData.PropCount <> 0 then
  begin

    GetMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
    try

      GetPropInfos(AClass1.ClassInfo, PropList);
      for
 i := 0 to ClassTypeData.PropCount - 1 do
        if
 not (PropList[i]^.PropType^.Kind = tkMethod) then
          {if Class1,2 is TControl/TWinControl on same form, its names must be unique}

          if
 PropList[i]^.Name <> 'Name' then
            if
 (PropList[i]^.PropType^.Kind = tkClass) then
            begin

              APersistent := TPersistent(GetObjectProp(AClass1, PropList[i]^.Name
, TPersistent));
            if
 APersistent <> nil then
              APersistent.Assign(TPersistent(GetObjectProp(AClass2, PropList[i]^.Name
, TPersistent)))
            end

            else

              SetPropValue(AClass1, PropList[i]^.Name
, GetPropValue(AClass2, PropList[i]^.Name));
    finally

      FreeMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
    end
;
  end
;
end
;


Note that this code skips object properties inherited other than TPersistent.



Tip by Gokhan Ersumer



Взято из http://www.lmc-mediaagentur.de/dpool

I need to get a list of strings (like a StringList) with the possible values for a TBrushStyle property (bsSolid, bsClear, bsHorizontal, for example). I want to build a ComboBox with this options. How can I set the property Items of my ComboBox directly with all the values from the enumerated type TBrushStyle? My ComboBox will be alike the Property Editor for this type.


You can use runtime type information (RTTI) to do that. Below is an example:



uses
 
  {...}
, TypInfo

procedure
 BrushStylesAsStrings(AList: TStrings);
var

  a: integer;
  pInfo: PTypeInfo;
  pEnum: PTypeData;
begin

  AList.Clear;
  pInfo := PTypeInfo(TypeInfo(TBrushStyle));
  pEnum := GetTypeData(pInfo);
  with
 pEnum^ do
  begin

    for
 a := MinValue to MaxValue do
      AList.Add(GetEnumName(pInfo, a));
  end
;
end




Tip by Sen



Взято из http://www.lmc-mediaagentur.de/dpool

I would like to change the font color on all components on a form at runtime (and the components owned by the components etc). I devised a recursive algorithm using RTTI that accepts a TComponent as a parameter. It works to some extent, but I still have to use 'if' statements to cast the object to a particular descendant, resulting in about 30 lines of code to test for all of the components I use. Also, some objects (TColumnTitle), are not descended from TComponent, even though they have a font property.

This may do the trick (with D6 and maybe D5):
uses

  TypInfo;

{ ... }

var

  i: integer;
  aFont: TFont;
begin

  for
 i := 0 to aComponent.ComponentCount - 1 do
  begin

    aFont := TFont(GetOrdProp(aComponent.Components[i], 'Font'
));
    if
 assigned(aFont) then
      aFont.Color := clWhite;
  end
;
end
;


With
 D4:


{ ... }

var

  i: integer;
  aFont: TFont;
  pi: PPropInfo;
begin

  for
 i := 0 to aComponent.ComponentCount - 1 do
  begin

    pi := GetPropInfo(aComponent.Components[i].ClassInfo, 'Font'
);
    if
 assigned(pi) then
      TFont(GetOrdProp(aComponent.Components[i],pi)).Color := clWhite;
  end
;
end
;




Tip by Charles McNicoll




Взято из http://www.lmc-mediaagentur.de/dpool

{ ... }
type

  PYourMethod = ^TYourMethod;
  TYourMethod = procedure
(S: stringof Object;


procedure
 TMainForm.Button1Click(Sender: TObject);
begin

  ExecMethodByName('SomeMethod'
);
end
;


procedure
 TMainForm.ExecMethodByName(AName: string);
var

  PAddr: PYourMethod;
  M: TMethod;
begin

  PAddr := MethodAddress(AName);
  if
 PAddr <> nil then
  begin

    M.Code := PAddr;
    M.Data := Self;
    TYourMethod(M)('hello'
);
  end
;
end
;


procedure
 TMainForm.SomeMethod(S: string);
begin

  ShowMessage(S);
end





Tip by Sasan Adami




Взято из http://www.lmc-mediaagentur.de/dpool

директивы условной компиляции
{$C+} и {$C-} - директивы проверки утверждений
{$I+} и {$I-} - директивы контроля ввода/вывода
{$M} и {$S} - директивы, определяющие размер стека

{$M+} и {$M-} - директивы информации времени выполнения о типах
{$Q+} и {$Q-} - директивы проверки переполнения целочисленных операций

{$R} - директива связывания ресурсов

{$R+} и {$R-} - директивы проверки диапазона

{$APPTYPE CONSOLE} - директива создания консольного приложения



1) Директивы компилятора, разрешающие или запрещающие проверку утверждений.

По умолчанию   {$C+} или {$ASSERTIONS ON}

Область действия локальная


Описание

Директивы компилятора $C разрешают или запрещают проверку утверждений. Они влияют на работу процедуры Assert,используемой при отладке программ. По умолчанию действует
директива {$C+} и процедура Assert генерирует исключение EAssertionFailed, если проверяемое утверждение ложно.

Так как эти проверки используются только в процессе отладки программы, то перед ее окончательной компиляцией следует указать директиву {$C-}. При этом работа процедур Assert будет блокировано и генерация исключений EassertionFailed производиться не будет.

Директивы действуют на весь файл исходного кода независимо от того, в каком месте файла они расположены.





2) Директивы компилятора, включающие и выключающие контроль файлового ввода-вывода.

По умолчанию {$I+} или {$IOCHECKS ON}

Область действия локальная

Описание

Директивы компилятора $I включают или выключают автоматический контроль результата вызова процедур ввода-вывода Object Pascal. Если действует директива {$I+}, то при возвращении процедурой ввода-вывода ненулевого значения генерируется
исключение EInOutError и в его свойство errorcode заносится код ошибки. Таким образом, при действующей директиве {$I+} операции ввода-вывода располагаются в блоке try...except, имеющем обработчик исключения EInOutError. Если такого блока нет, то обработка производится методом TApplication.HandleException.

Если действует директива {$I-}, то исключение не генерируется. В этом случае проверить, была ли ошибка, или ее не было, можно, обратившись к функции IOResult. Эта функция очищает ошибку и возвращает ее код, который затем можно анализировать. Типичное применение директивы {$I-} и функции IOResult демонстрирует следующий пример:

{$I-}

AssignFile(F,s);
Rewrite(F);

{$I+}
i:=IOResult;
if i<>0 then

case i of
      2: ..........
      3: ..........
   end;

В этом примере на время открытия файла отключается проверка ошибок ввода вывода, затем она опять включается, переменной i присваивается значение, возвращаемое функцией IOResult и, если это значение не равно нулю (есть ошибка), то предпринимаются какие-то действия в зависимости от кода ошибки. Подобный стиль программирования был типичен до введения в Object Pascal механизма обработки исключений. Однако сейчас, по-видимому, подобный стиль устарел и применение директив $I потеряло былое значение.


3) Директивы компилятора, определяющие размер стека

По умолчанию {$M 16384,1048576}


Область действия глобальная

Описание

Локальные переменные в процедурах и функциях размещаются в стеке приложения. При каждом вызове процедуры или функции ее локальные переменные помещаются в стек. При выходе из процедуры или функции эти локальные процедуры удаляются из стека.
Директивы компилятора $M задают параметры стека приложения: его минимальный и максимальный размеры. Приложение всегда гарантированно имеет размер стека, равный его минимальной величине. Если при запуске приложения Windows обнаруживает, что не может
выделить этот минимальный объем памяти, то выдается сообщение об этой ошибке.

Если во время работы выясняется, что минимального размера стека не хватает, то размер увеличивается на 4 K, но не более, чем до установленного директивой максимального размера. Если увеличение размера стека невозможно из-за нехватки памяти или из-за достижения его максимальной величины, генерируется исключение EStackOverflow. Минимальный размер стека по умолчанию равен 16384 (16K). Этот размер может изменяться параметром minstacksize
директивы {$M} или параметром number директивы {$MINSTACKSIZE}.

Максимальный размер стека по умолчанию равен 1,048,576 (1M). Этот размер может изменяться параметром maxstacksize директивы {$M} или параметром number директивы {$MAXSTACKSIZE number}. Значение минимального размера стека может задаваться целым числом в диапазоне между1024 и 2147483647. Значение максимального размера стека должно быть не менее минимального размера и не более 2147483647. Директивы задания размера стека могут включаться только в программу и не должны использоваться в библиотеках и модулях.

В Delphi 1 имеется процедура компилятора {$S}, осуществляющая переключение контроля переполнения стека. Теперь этот процесс полностью автоматизирован и директива {$S} оставлена только для обратной совместимости.


4) Директивы компилятора, включающие и выключающие генерацию информации времени выполнения о типах (runtime type information - RTTI).

По умолчанию {$M-} или {$ TYPEINFO OFF}

Область действия локальная

Описание

Директивы компилятора $I включают или выключают генерацию информации времени выполнения о типах (runtime type information - RTTI). Если класс объявляется в состоянии {$M+} или является производным от класса объявленного в этом состоянии, то компилятор генерирует RTTI о его полях, методах и свойствах, объявленных в разделе published. В противном
случае раздел published в классе не допускается. Класс TPersistent, являющийся предшественником большинства классов Delphi и все классов компонентов, объявлен в модуле Classes в состоянии {$M+}. Так что для всех классов, производных от него, заботиться о директиве {$M+}не приходится.





5) Директивы компилятора, включающие и выключающие проверку переполнения при целочисленных операциях

По умолчанию {$Q-} или {$OVERFLOWCHECKS OFF}

Область действия локальная

Описание

Директивы компилятора $Q включают или выключают проверку переполнения при целочисленных операциях. Под переполнением понимается получение результата, который не может сохраняться в регистре компьютера. При включенной директиве {$Q+} проверяется переполнение при целочисленных операциях +, -, *, Abs, Sqr, Succ, Pred, Inc и Dec. После каждой из этих операций размещается код, осуществляющий соответствующую проверку. Если обнаружено переполнение,
то генерируется исключение EIntOverflow. Если это исключение не может быть обработано, выполнение программы завершается.

Директивы $Q проверяют только результат арифметических операций. Обычно они используются совместно с директивами {$R}, проверяющими диапазон значений при присваивании.
Директива {$Q+} замедляет выполнение программы и увеличивает ее размер. Поэтому обычно она используется только во время отладки программы. Однако, надо отдавать себе отчет, что отключение этой директивы приведет к появлению ошибочных результатов расчета в случаях, если переполнение действительно произойдет во время выполнении программы. Причем сообщений о подобных ошибках не будет.





6) Директива компилятора, связывающая с выполняемым модулем файлы ресурсов

Область действия локальная

Описание

Директива компилятора {$R} указывает файлы ресурсов (.DFM, .RES), которые должны быть включены в выполняемый модуль или в библиотеку. Указанный файл должен быть файлом ресурсов Windows. По умолчанию расширение файлов ресурсов - .RES. В процессе компоновки компилированной программы или библиотеки файлы, указанные в директивах {$R}, копируются в
выполняемый модуль. Компоновщик Delphi ищет эти файлы сначала в том каталоге, в котором расположен модуль, содержащий директиву {$R}, а затем в каталогах, указанных при выполнении команды главного меню Project | Options на странице Directories/Conditionals диалогового окна в опции Search path или в опции /R командной строки DCC32.

При генерации кода модуля, содержащего форму, Delphi автоматически включает в файл .pas директиву {$R *.DFM}, обеспечивающую компоновку файлов ресурсов форм. Эту директиву нельзя удалять из текста модуля, так как в противном случае загрузочный модуль не будет создан и сгенерируется исключение EResNotFound.






7) Директивы компилятора, включающие и выключающие проверку диапазона целочисленных значений и индексов

По умолчанию {$R-} или {$RANGECHECKS OFF}

Область действия локальная

Описание

Директивы компилятора $R включают или выключают проверку диапазона целочисленных значений и индексов. Если включена директива {$R+}, то все индексы массивов и строк и все присваивания скалярным переменным и переменным с ограниченным диапазоном значений проверяются на соответствие значения допустимому диапазону. Если требования
диапазона нарушены или присваиваемое значение слишком велико, генерируется исключение ERangeError. Если оно не может быть перехвачено, выполнение программы завершается.

Проверка диапазона длинных строк типа Long strings не производится.
Директива {$R+} замедляет работу приложения и увеличивает его размер. Поэтому она обычно используется только во время отладки.


8) Директива компилятора, связывающая с выполняемым модулем файлы ресурсов

Область действия локальная

Описание

Директива компилятора {$R} указывает файлы ресурсов (.DFM, .RES), которые должны быть включены в выполняемый модуль или в библиотеку. Указанный файл должен быть файлом ресурсов Windows. По умолчанию расширение файлов ресурсов - .RES.
В процессе компоновки компилированной программы или библиотеки файлы, указанные в директивах {$R}, копируются в выполняемый модуль. Компоновщик Delphi ищет эти файлы сначала в том каталоге, в котором расположен модуль, содержащий директиву {$R}, а затем в каталогах, указанных при выполнении команды главного меню Project | Options на странице Directories/Conditionals диалогового окна в опции Search path или в опции /R командной строки DCC32.

При генерации кода модуля, содержащего форму, Delphi автоматически включает в файл .pas директиву {$R *.DFM}, обеспечивающую компоновку файлов ресурсов форм. Эту директиву нельзя удалять из текста модуля, так как в противном случае загрузочный модуль не будет создан и сгенерируется исключение EResNotFound.

Автор ответа: Cashey
Взято с Vingrad.ru http://forum.vingrad.ru


Взято из FAQ: http://blackman.km.ru/myfaq/cont4.phtml
Если вы присвоили свойству имя TableName, то полный цикл создания
редактора свойств включает следующие шаги:
Опишите класс редактора свойства:


type
TTableNameProperty = class
(TStringProperty)
function
 GetAttributes: TPropertyAttributes; override;
procedure
 GetValues(Proc: TGetStrProc); override;
end
;
implementation

{ TTableNameProperty }

function
 TTableNameProperty.GetAttributes: TPropertyAttributes;
begin

Result := [paValueList];
end
;
procedure
 TTableNameProperty.GetValues(Proc: TGetStrProc);
var

TableName: String
;
I: Integer;
begin

{ здесь вы должны добавить свой код, ?тобы с помощью цикла обойти имена всех
таблиц, вклю?енных в список }

for
 I := 0 to ???? do begin
TableName := ????[I];
Proc(TableName);
end
;
end


Затем зарегистрируйте данный редактор свойства следующим образом:
 RegisterPropertyEditor(TypeInfo(string), TcsNotebook, 'TableName', TTableNameProperty);    


Взято с Vingrad.ru http://forum.vingrad.ru

F1, Ctrl-F1 - контекстная помощь
F3 - продолжить поиск
F4 - выполнить программу до положения курсора
F5 - поставить Break Point
F7 - трассировать с заходом в процедуры
F8 - трассировать без захода в процедуры
F9 - запустить программу
F10, Ctrl-F10 - активизировать главное меню
F11 - открыть/закрыть Object Inspector
F12 - переход между формой и кодом
Ctrl-F2 - прервать выполнение программы
Ctrl-F3 - посмотреть стек
Ctrl-F4 - закрыть текущий модуль
Ctrl-F5 - Watch List
Ctrl-F7 - Evalute/Modify (просмотр значений переменных и их изменение)
Ctrl-F9 - Компиллировать проэкт
Ctrl-F11 - Открыть проэкт
Ctrl-F12 - Список модулей проэкта
Shift-F7 - Трассировка заходя в каждую процедуру и перескакивание в каждое возникающее событие
Shift-F10 - всплывающее меню
Shift-F11 - добавить модуль к проэкту
Shift-F12 - список форм проэкта для быстрой навигации
Alt-F4, Ctrl-Shift-F4 - закрыть проэкт и все файлы.
Alt-F6 - палитра выравнивания
Alt-Ctrl-F11 - Мененджер проэктов
Alt-Shift-F4 - Закрыть все окна, но проэкт не закрывать
Ctrl-Shift-0..9 - Поставить метку 0..9
Ctrl-0..9 - Перейти на метку 0..9
Alt-0 - Список окон
Ctrl-Enter - Открыть файл с именем стова на котором курсор стоит
Ctrl+клик мышкой на слове - перейти на определение этого слова
Alt+функции выделения текста (мышкой или клавиатурой) - выделение вертикального блока
Ctrl-Shift-Up/Down - переход от объявления процедуры к ее реализации
Ctrl-Shift-C - закончить метод (если он описан - создать шаблон для реализации,
если есть реализация - объявить метод)
Ctrl-Shift-E - открыть эксплорер кода
Ctrl-Shift-R - начать/завершить запись макро
Ctrl-Shift-P - выполнить записанное макро
Ctrl-Shift-T - добавить в To Do лист
Ctrl-Shift-U - уменьшить отступ выделенного блока
Ctrl-Shift-I - Увеличить отступ выделенного блока
Ctrl-Shift-S - Grep Search
Ctrl-Shift-G - Вставить GUID
Ctrl-Shift-B - Посмотреть иерархию классов
Ctrl-Alt-W - Watch List
Ctrl-Alt-R - Grep Result
Ctrl-Alt-T - Список потоков проэкта
Ctrl-Alt-A - Вставить дату
Ctrl-Alt-S - Вызовы стэка
Ctrl-Alt-H - Шаблон для документации модуля
Ctrl-Alt-L - Локальные переменные
Ctrl-Alt-V - История событий
Ctrl-Alt-B - Список Break Points
Ctrl-Alt-M - Модули
Ctrl-N - Вставить пустую сторку, курсор остается на текущей строке
Ctrl-M, Enter - Вставить пустую сторку, курсор переходит на следующую строку
Ctrl-E - Поиск по мерре введения символов (Incremental Search)
Ctrl-R - Search and Replace
Ctrl-A - Выделить весь текст (только дельфи 6)
Ctrl-T - Удалить от курсора до конца слова
Ctrl-Y - Удалить строку
Ctrl-O + O - Вставить все текущие опции компилляции по позиции курсора
Ctrl-P - префикс, после которого можно вставить любой ASCII код
Ctrl-S - сохранить текущий файл
Ctrl-F - открыть диалог поиска
Ctrl-J - лист шаблонов
Ctrl-K + С - копирование блока без буфера обмена
Ctrl-Z - отмена
Ctrl-X - вырезать
Ctrl-С - копировать
Ctrl-V - вставить
Ctrl-B - список буфферов

Автор ответа: Vit
Взято с Vingrad.ru http://forum.vingrad.ru



Form

Tab Selects the next component
Shift+Tab Selects the previous component
Arrow Keys Selects the nearest component in the direction pressed
Ctrl+Arrow Keys Moves the selected component one pixel at a time
Shift+Arrow Keys Moves the selected component one pixel at a time
Ctrl+Shift+Arrow Keys Moves the selected component one grid at a time (when Snap to Grid is enabled)
Del Deletes the selected component
Esc Selects the containing group (usually the form or group box)

F11 Toggles control between the Object Inspector and the last active form or unit
F12 Toggles between the form and its associated unit
Ctrl+F12 Displays the View Unit dialog box
Shift+F12 Displays the View Form dialog box


Project Manager keyboard shortcuts

Arrow Keys Selects forms and units
Alt+A Adds a form or unit to the project
Alt+R Removes a form or unit from the project
Alt+U Views the selected unit
Alt+F Views the selected form
Alt+O Displays the Project Options dialog box
Alt+D Updates the current project
Enter Views the selected unit
Shift+Enter Views the selected form
Ins Adds a file to the project
Del Removes a file from the project


Object Inspector keyboard shortcuts

Ctrl+I Opens the Object Selector
Up and Down Arrow Keys Selects properties or event handlers
Left and Right Arrow Keys Edits the value in the value or event column
Tab Toggles between the property and value columns in the Object Inspector
Tab+ Jumps directly to the first property beginning with the letter
Ctrl+Tab Toggles between the properties and events tabs in the Object Inspector
Page Up Moves up one screen of properties

Page Down Moves down one screen of properties
Alt+F10 Toggles expand and contract
Alt+Down Opens a drop-down list for a property.
Ctrl+Down Opens the object list drop-down.
Ctrl+Enter Selects the ellipsis button (if available) in a selected property.


Package editor

Enter Lets you view the selected unit's source code.
Ins Adds a unit to the current folder (Contains or Requires).
Del Removes the selected item from the package.
Ctrl+B Compiles the current package. If changes to the package are required, a dialog box appears that lists the changes that will be made to the package before it is compiled.
Ctrl+I Installs the current package as a design time package. If changes to the package are required, a dialog box appears that lists the changes that will be made to the package before it is compiled.

CPU Window

Shift+Left Arrow Move left one pane.
Shift+Right Arrow Move right one pane
Shift+Up Arrow Move up one pane.
Shift+Down Arrow Move down one pane.

Автор ответа:
Admin
Взято с Vingrad.ru http://forum.vingrad.ru

Иногда надо выполнить разный код в зависимости от версии Дельфи, особенно актуально это при разработки компонентов и модулей, которые используются в разных приложениях.

В Дельфи предопределены специальные константы компилляции для этого:

Ver80 - Делфи 1
Ver90 - Делфи 2
Ver93 - С Buider 1
Ver100 - Дельфи 3
Ver110 - С Buider 3
Ver120 - Дельфи 4
Ver125 - С Buider 4
Ver130 - Дельфи 5
Ver140 - Дельфи 6
Ver150 - Дельфи 7

Пример использования:

procedure
 TForm1.Button2Click(Sender: TObject);
const
 Version=

{$Ifdef Ver80}'Делфи 1';{$EndIf}    

{$Ifdef Ver90}'Делфи 2';{$EndIf}   

{$Ifdef Ver100}'Дельфи 3';{$EndIf}  

{$Ifdef Ver120}'Дельфи 4';{$EndIf}   

{$Ifdef Ver130}'Дельфи 5 ';{$EndIf}  

{$Ifdef Ver140}'Дельфи 6';{$EndIf}  

{$Ifdef Ver150}'Дельфи 7';{$EndIf}   


begin

  ShowMessage('Для компилляции этой программы был использован '
+Version);
end
;

Автор Vit
Взято с Vingrad.ru http://forum.vingrad.ru

Версии компиллятора

Ver80 - Делфи 1
Ver90 - Делфи 2
Ver93 - С Buider 1
Ver100 - Дельфи 3
Ver110 - С Buider 3
Ver120 - Дельфи 4
Ver125 - С Buider 4
Ver130 - Дельфи 5
Ver140 - Дельфи 6
Ver150 - Дельфи 7
Ver160 - Дельфи 8
KYLIX - Kylix 1
KYLIX2 - Kylix 2
KYLIX3 - Kylix 3
KYLIX4 - Kylix 4



Платформа: (определена для Дельфи 6 и выше)

Linux
MSWindows




Среда разработки:

DELPHI
BCB

Взято с Vingrad.ru http://forum.vingrad.ru


{....} 

uses
 ToolsApi, Menus; 

{....}
 

var
 
  item: TMenuItem; 
begin
 
  {get reference to delphi's mainmenu. You can handle it like a common TMainMenu}
 
  with
 (BorlandIDEServices as INTAServices).GetMainMenu do 
  begin
 
    item := TMenuItem.Create(nil
); 
    item.Caption := 'A Mewn caption'

    Items.Add(item); 
  end

end


Взято с сайта http://www.swissdelphicenter.ch/en/tipsindex.php


This unit can be compiled into a package and will then appear in the delphi 
Help menu. 
}
 
unit
 SDCSimpleExpert; 

interface
 

uses
 ToolsApi; 

type
 
  TSDCSimpleExpert = class
(TNotifierObject, IOTAMenuWizard, IOTAWizard) 
  public
 
    function
 GetIDString: string
    function
 GetName: string
    function
 GetState: TWizardState; 
    procedure
 Execute; 
    function
 GetMenuText: string
  end


procedure
 Register

implementation
 

uses
 Dialogs; 

procedure
 Register
begin
 
  {register expert}
 
  RegisterPackageWizard(TSDCSimpleExpert.Create); 
end


{ TSDCSimpleExpert }
 

procedure
 TSDCSimpleExpert.Execute; 
begin
 
  {code to execute when menu item is clicked}
 
  ShowMessage('Hello SwissDelphiCenter Simple Expert.'
); 
end


function
 TSDCSimpleExpert.GetIDString: string
begin
 
  {unique expert identifier}
 
  Result := 'SwissDelphiCenter.SimpleExpert'

end


function
 TSDCSimpleExpert.GetMenuText: string
begin
 
  {caption of menu item in help menu}
 
  Result := 'SwissDelphiCenter Simple Expert'

end


function
 TSDCSimpleExpert.GetName: string
begin
 
  {name of the expert}
 
  Result := 'SwissDelphiCenter Simple Expert'

end


function
 TSDCSimpleExpert.GetState: TWizardState; 
begin
 
  Result := [wsEnabled]; 
end


end


Взято с сайта http://www.swissdelphicenter.ch/en/tipsindex.php

Для этого достаточно текущее разрешение экрана и в соответствии с ним изменить дескриптор иконки приложения. Естевственно, что Вам прийдётся создать в ресурсах новые иконки.

Поместите следующий код в файл проекта (.DPR) Вашего приложения:

  Application.Initialize; 
  Application.CreateForm(TForm1, Form1); 
  CASE
 GetDeviceCaps(GetDC(Form1.Handle), HORZRES) of 
     640
 : Application.Icon.Handle := LoadIcon (hInstance, 'ICON640'); 
     800
 : Application.Icon.Handle := LoadIcon (hInstance, 'ICON800'); 
    1024
 : Application.Icon.Handle := LoadIcon (hInstance, 'ICON1024'); 
    1280
 : Application.Icon.Handle := LoadIcon (hInstance, 'ICON1280'); 
  END

  Application.Run; 

Взято с Исходников.ru http://www.sources.ru/delphi_src1.shtml

1-50 51-94
Поиск

Наш Банер

Мы будем вам признательны, если вы разместите нашу кнопку у себя на сайте. Если вы хотите обменяться с нами баннерами, пишите в гостевую книгу:

Все для программиста

Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz


  • Copyright MyCorp © 2024Бесплатный хостинг uCoz