Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  15:53[Войти] | [Зарегистрироваться]
Ответ на вопрос № 58782

23-01-2008 12:52
Подскажите, как получить адрес процедуры в классе?
есть класс


TMyClass = class
  public
    procedure MyProc;
    procedure MyProc_2;
  end;

implementation

procedure TMyClass.MyProc;
  begin
    //...
  end;
procedure TMyClass.MyProc_2;
  var
    P: Pointer;
  begin
    P:=@Self.MyProc;  //тут выскакивает ошибка
  end;



При попытке получить адрес, выскакивает ошибка: "Variable required".

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

08-02-2008 11:32 | Комментарий к предыдущим ответам
есть четыре метода решения вопроса.
Добавлю что метод "Решение 4. Универсальный способ." не будет нормально работать на современных процессорах/операционках, если не выставить создаваемому блоку памяти доступ как минимум на PAGE_EXECUTE (нормальный вариант можно посмотреть тремя сообщениями ниже).
А способ "Решение 3. MakeObjectInstance." вообще мало для чего пригоден потому как жёстко завязан на формат TMessage, то есть там придётся по всякому извращаться, например передавать результат callback-функции через стек.

08-02-2008 10:03 | Сообщение от автора вопроса
В итоге я просто переписал код DLL, дабы она ожидала TNotifyEvent, благо
у меня были сорцы.
Но, если кто столкнётся с подобным вопросом, то вот тут:
http://tokolist.com/articles.php?methodtoproc
есть четыре метода решения вопроса. Статья так и называется:
"Callback-функция как метод класса в Delphi".

26-01-2008 05:26
Код из модуля по приведенной мною ссылке делает то же самое, с минимальными и непринципиальными отличиями.
Именно так, там даже лучше, с точки зрения "жадности" к памяти, ну а я просто неслишком внимательно читал и не заметил эту ссылку.

26-01-2008 00:04
2 DRON

Код из модуля по приведенной мною ссылке делает то же самое, с минимальными и непринципиальными отличиями.
 NS

25-01-2008 16:42
В инете можно найти множество примеров по преобразованию методов в функции. Например в библиотеке madBasic есть функция MethodToProcedure и даже обратная ей ProcedureToMethod. Вот их исходники:

function MethodToProcedure(self: TObject; methodAddr: pointer) : pointer;
type
  TMethodToProc = packed record
    popEax  : byte;                  // $58      pop EAX
    pushSelf : record                //          push self
                opcode  : byte;      // $B8
                self    : pointer;  // self
              end;
    pushEax  : byte;                  // $50      push EAX
    jump    : record                //          jmp [target]
                opcode  : byte;      // $FF
                modRm  : byte;      // $25
                pTarget : ^pointer;  // @target
                target  : pointer;  //          @MethodAddr
              end;
  end;
var mtp : ^TMethodToProc absolute result;
begin
  mtp := VirtualAlloc(nil, sizeOf(mtp^), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  with mtp^ do begin
    popEax          := $58;
    pushSelf.opcode := $68;
    pushSelf.self  := self;
    pushEax        := $50;
    jump.opcode    := $FF;
    jump.modRm      := $25;
    jump.pTarget    := @jump.target;
    jump.target    := methodAddr;
  end;
end;

function MethodToProcedure(method: TMethod) : pointer;
begin
  result := MethodToProcedure(TObject(method.data), method.code);
end;

function ProcedureToMethod(self: TObject; procAddr: pointer) : TMethod;
begin
  result.Data := self;
  result.Code := procAddr;
end;



Есть ещё вариант:
3. В DLL передаётся процедура, в приложении используется метод класса. А превратить одно в другое нам поможет функция MakeObjectInstance.

MakeObjectInstance поддерживает только WndProc-совместимые функции.

25-01-2008 07:55 | Комментарий к предыдущим ответам
Если DLL Ваша, то у Вас два честных варианта:
1. Переписать функцию в DLL, чтобы ей передавася метод, а не процедура.
2. Передавать в функцию DLL специально созданную процедуру, а не метод класса.

Есть ещё вариант:
3. В DLL передаётся процедура, в приложении используется метод класса. А превратить одно в другое нам поможет функция MakeObjectInstance.

25-01-2008 07:33 | Комментарий к предыдущим ответам
Чукчи -- не читатели. Чукчи -- писатели ;)

25-01-2008 06:44
Quote]Т.е. как я понимаю, единственный вариант решения вопроса - это описать вне класса обычную процедуру
и передавать ссылку на неё?
Именно так.
Метод и процедура, внешне похожие по передаваемым параметрам (от бишь например procedure  и procedure of object)  на амом деле  - две большие разницы. У них разный стек. Дело в том, что в метод дельфа неявно в качестве параметра передает указатель Self.  Т.е.
procedure of object  - это (с т.з. стека процедуры) эквивалентно procedure(Self:pointer).


25-01-2008 06:35
Господа, ну что вы человека совсем запутали.
Проблема решается стандартно.
Нужно написать процедуру в той форме, которую принимает DLL.
Внутри этой процедуры вызвать метод класса по указателю на класс, который может быть передан двумя способами:
- если процедура без параметров, то указатель на класс передаеть через глобальную переменную;
- если процедура имеет параметром указатель, то передать указатель на класс через этот параметр.

25-01-2008 03:16
Если DLL Ваша, то у Вас два честных варианта:
1. Переписать функцию в DLL, чтобы ей передавася метод, а не процедура.
2. Передавать в функцию DLL специально созданную процедуру, а не метод класса.

Выбор за Вами ;-)

25-01-2008 02:54 | Сообщение от автора вопроса
Всем спасибо, за подробное объяснение.
Выход как я понял один - пересобрать DLL, изменив процедуру создания таймера таким образом, чтобы она ожидала TNotifyEvent.

25-01-2008 00:01 | Комментарий к предыдущим ответам
>>> но я все равно не понял по поводу чего начался спор
Перечитал и сам не понял. Наверное, просто поговорить захотелось с хорошим человеком ;-)

Просто у автора какая-то стороння DLL (по крайней мере, я так понял) и навряд ли в ней вызывается именно TNotifyEvent. Скорее всего, обычная процедура. Вот всех и переклинило на разнице между процедурами и методами.

P.S. Хм... Значит нет в Питере никакой аномалии? А я уже собрался научное иссследование выполнять :D

24-01-2008 19:20 | Комментарий к предыдущим ответам
все это замечательно, но я все равно не понял по поводу чего начался спор - что я написал в своем примере такого, что может нарушить устойчивость системы?)) а то както получается разговор немого с глухим) а на счет того что вы мне прокоментировали я с вами полностю согласен))
если автору был важен НЕПОСРЕДСТВЕННЫЙ адрес процедуры в классе то да кончено нада писать addr(Proc) . но на мой взгляд это уже немного отклонение от ООП() - мало ли авдруг автор решит передать туда процедуру из приватных или защищенных. работать - не спорю будет - но ООП не для того создавался чтобы его обходить - проще(лучьше сказать грамотнее) тогдапосылать сообщение классу чтобы он вызвал свою внутреннюю процедуру

24-01-2008 09:28 | Комментарий к предыдущим ответам
>>> я так понял что вы мне эту историю рассказали поповоду того что <...>
Я Вам эту историю рассказал по поводу того, что хороший стиль программирования подразумевает учет всех возможных вариантов. Необходимость этого существенно возрастает если Вы при разработке используете недокументированные возможности или полузаконные приемы, так как в этом случае разработчик инструментальных средств Вам вообще ничего не гарантирует.

Данный конкретный прием не является законным. И я уже показал одну проблему, которая может возникнуть, и набросал еще гипотез о возможном возникновении проблем. То есть, мало сказать, какой оператор использовать, надо еще определить, в каком случае его можно использовать, а в каком не стоит, так как это может привести к печальным последствиям. Называется это область применимости метода. Область применимости документированных возможностей приводится в хелпе и прочей документации. Ответственность за это несет Borland и CodeGear. Область применимости данного метода не приводится нигде. Надо самим НИР выполнять. Откачества проведения этого НИРа зависит дальнейшая судьба разработки.

>>> ну я вам не буду рассказывать про жизненный цикл прогр продуктов
Делайте разницу между жизненным циклом тиражируемого коммерческого программного продукта и системы собственной разработки для внутреннего употребления. У меня программы на Delphi-1 (и даже мелкие утилитки на Turbo Pascal) живы и до сих пор работают. А вот система, конечная версия которой была написана на Delphi-3, благополучно загнулась. И произошло это только потому, что автор в процессе разработкипрорабатывал только основную линию, но не тратил время на тщательную проработку деталей. И жила эта система ровно до тех пор, пока разработчик был доступен и на вносил в систему правки на каждый случай, когда пользователи споткались о непроработанную неучтенную им ситуацию.

>>> это я к тому что лень - двигатель прогресса - чем проще код тем лучьше
Невольно возникает желание поиграть словами и ответить Вам старой русской поговоркой "Простота хуже воровства" ;-)

Дабы все же заниматься делом, а не жонглировать словами поясню, что приведенный Вами упрощенный вариант вычисления значения логического выражения является документированной возможностью языка, то есть разработчик гарантирует, что такая форма записи корректна во всех ситуациях, а также гарантирует, что эта корректность сохранится и в последующих версиях языка. Могу привести даже более яркий пример. Антон Григорьев не любит в своем коде ставить точку-с-запятой после оператора, ха которым следует слово end. И это тоже не хак. Это документированная возможность языка, которая изначально постулировалась Виртом. Есть мой любимый прием подмены классов VCL собственными модификациями этих классов. Полузаконный прием. Но после тщательного всестороннего анализа и обсуждения было определено, что в существующих условиях использование данного приема безопасно. А также были выявлены условия, при возникновении которых применять этот прием бездумно не стоит.

Еще разобраться, как лучше поступить ленивому человеку. Что легче: написать чуть более длинный код или обосновать применимость метода, который позволяет писть более экономный код :D

P.S. И маленькая просьба: сообщения, которые не являются непосредственным ответом на вопрос, принято помечать как "Комментарий к предыдущим ответам".

24-01-2008 07:41
ухты))) мир тесен))) я так понял что вы мне эту историю рассказали поповоду того что  я решил поставить там TNotyfyEvent)) или нет - если да - то в 99% случаях этот код подойдет для той проблемы что представил автор. а на счет 1996-1999 - ну я вам не буду рассказывать про жизненный цикл прогр продуктов)))ведь мы пишем куски кода на асме - а это самый опасный участок в плане переносимости на новые платформы.  если вы про то что можно разными путями решать данную проблему то я отвечу(как я уже гдето писал) что да можно написать
If P then  а можно и If P=true then а можно и как некоторые тут предложили If BoolToStr(P)='True' then...)))) это я к тому что лень - двигатель прогресса - чем проще код тем лучьше.

24-01-2008 06:52 | Комментарий к предыдущим ответам
to Knight:
Знаете, Ваш "прямолинейный" подход напомнил мне подход к работе одного моего знакомого. При разработке он действовал прямолинейно, как перпендикуляр. Детально расписать не получится, но если выразиться образно, то получится что-то вроде "Если нажата эта клавиша, то делаем это, а если эта, то вот это". О том, что кроме этих двух клавиш на клавиатуре остается еще сотня, он просто не задумывался. В 1996 году он написал средней сложности программу. И периодически занимался ее переделкой (инициированной, в основном, замечаниями пользователей) вплоть до 1999 года, после чего благополучно сменил место работы. Годика через два после очередной смены софта его программа напрочь отказалась запускаться. Исправить ситуацию не удалось никакими администраторскими ухищрениями. Держать для работы с этой программой второй пентиум с Вин-95 посчитали излишней роскошью, поэтому программу просто выбросили. Благо это был не коммерческий продукт, а инструмент для автоматизации собственной деятельности.

P.S. Кстати, этот человек тоже с Петропавловска-Камчатского ;-) У ваас там какая-то аномалия наверное, потому что всего лишь 30 км на север (Елизово, то бишь я) и такого уже нет :D

24-01-2008 06:30
что вы раздули из мухи слона прямо уж не знаю даже)))
ну вы передаете адрес процедуры - и ошибка - ясен пень вам то нада передавать метод - это как уже упомянали адрес процедуры в совокупности с адресом класса
так в чем проблема пишем
procedure DoMyProc(Proc : TNotifyEvent);
begin
  Proc(nil);
end;

procedure TForm1.A;
begin
  showmessage('sd');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  DoMyProc(A);
end;
все пашет как миленькое))) сам тестил - че спрашивется такие дебаты устроили

24-01-2008 04:03 | Комментарий к предыдущим ответам
Если изменим модель вызова и будем передавать параметры через стек, то теоретически возможны проблемы
То-то я думаю, почему не падает при модели вызова register :-)

24-01-2008 04:00
to Котопёс:
Если интересно, то можете для общего развития посмотреть еще и вот эту статью
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=578

Только это... обсуждение статьи тоже посмотрите.

24-01-2008 03:54
>>> но нужно это как-то убедительно доказать
Первый вариант, который касается использования полей объекта, я уже доказал. По поводу остальных пока только гипотезы, которые нужно проверить, чтобы доказательство выглядело убедительно. Излагаю в форме гипотез.

1. Вызов виртуального метода. Какая именно из реализаций метода будет вызвана, зависит от того, к какому именно классу относится данный объект. Не факт, что без знания объекта будет вызван именно тот метод, который нужен, а не реализация его для предка.

2. Передача параметров через стек. Каюсь, я вчера все же заглянул немного в реализацию. При передаче параметров через регистры в памяти создается структура TMethod (сначала указатель на процедуру, потом указатель на класс), а в функцию передается указатель на эту структуру. Детали не рыл, но, вроде бы, безопасно. Если изменим модель вызова и будем передавать параметры через стек, то теоретически возможны проблемы, так как в этом случае ссылка на объект должна тоже передаваться через стек, но функция из DLL этого не знает. Могут возникнуть расхождения при освобождении стека.

На всякий случай повторю: это гипотезы. Их сначала нужно проверить. Ну, или знать "от" и "до" все нюансы вызовов методов и процедур.

24-01-2008 03:37 | Комментарий к предыдущим ответам
Если procedure DoMyProc(ProcAddress: Pointer); описана с моделью вызова stdcall в случае, описанном Сергем Хачатуровым, рискуем получить AV при выходе из TForm1.BitBtn1Click.

З.Ы. Вспомнился вопрос, где автор хотел передать для вызова обычную процедуру там, где требовалась передача метода »вопрос КС №56522«.
Может чем поможет.

24-01-2008 03:25
2 Сергей Хачатуров

>>>единственный вариант решения вопроса - это описать вне класса обычную процедуру, но нужно это как-то убедительно доказать

В смысле, что доказать? Что метод не совместим с обычной процедурой? Так это просто - в метод передается еще один неявный параметр - Self, кроме тех, что явно заявлены в его заголовке.
 NS

24-01-2008 03:22 | Сообщение от автора вопроса
Спасибо.
Вечером буду пробовать :)

24-01-2008 03:22
>>>Т.е. как я понимаю, единственный вариант решения вопроса - это описать вне класса обычную процедуру и передавать ссылку на неё?

Вот здесь
http://kladovka.net.ru/index.cgi?pid=dir&rid=8&ppn=2
лежит модуль makeinstance.zip, он позволяет это ограничение обойти для любых stdcall-функций. Работает по принципу MakeObjectInstance.
 NS

24-01-2008 03:09
если процедура, пусть и описанная внутри класса, не использует его полей, то вполне проходит то, что я написал.

если использует, то на первый взгляд единственный вариант решения вопроса - это описать вне класса обычную процедуру, но нужно это как-то убедительно доказать

24-01-2008 03:07
>>> Т.е. как я понимаю, единственный вариант решения вопроса - это описать вне класса обычную процедуру и передавать ссылку на неё?
Это честный вариант. Можно воспользоваться и нечестным, но тогда (как и всегда при использованеии читерских приемов и недокументированных возможностей) вся ответственность за возможные сбои при работе программы ляжет на Вас.

Сергей Хачатуров привел пример работоспособного вызова метода класса таким способом.

24-01-2008 02:59 | Сообщение от автора вопроса
Т.е. как я понимаю, единственный вариант решения вопроса - это описать вне класса обычную процедуру
и передавать ссылку на неё?

24-01-2008 02:13
Мне необходим именно указатель на метод
Эта процедура описанна в моём классе как событие
Скорее всего чужая DLL понятия не имеет о классах Delphi и их методах.

требует в качестве параметра именно указатель на процедуру, которою будет вызывать по этому таймеру
Обычно есть возможность передать в указанную процедуру обратного вызова произвольный параметр типа Pointer. И передавать в нем ссылку на Ваш класс (так реализован класс TTread).

Например, если прототип процедуры, вызываемой по таймеру


VOID CALLBACK TimerCallback(
  PVOID lpParameter);


то при создании таймера можно указать параметр для функции обратного вызова и передать в нем Pointer(SomeObject).
То в lpParameter можно передать

24-01-2008 00:05
>>> ну... а что получится?
Ничего не получится. Текста в окошке нет.

>>> ссылка на метод передается, процедура выполняется, что и требовалось доказать...
Эт прям как сисадмин на стрельбище...
"С моей стороны пули вылетели. Если не можете найти их в мишени, то проблемы у вас" ;-)

Пока спал, продолжал думать (во, запала задача!). Насчет утечек, скорее всего, я не прав. Но зато придумал еще один потенциальнго сбойный момент дл такого подхода, касающийся виртульных методов. Но на проверку сейчас уже нет времени :(

23-01-2008 18:27 | Комментарий к предыдущим ответам
ну... а что получится?

ссылка на метод передается, процедура выполняется, что и требовалось доказать... а переменная... вопрос-то был в сущности про то "как получить .. процедуру ... , которою будет вызывать таймер"

А Ваш подход основан в основном на остутствии фундаментальных знаний (для чего и пишем, что неправильно - укажут на ошибки умные люди)

:-)

23-01-2008 17:44
Ну, хорошо. А если немного изменить Ваш код и написать так, то как Вы думаете, что получится?

type
  TMyMethod = procedure of object;

  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    procedure BitBtn1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    FMsgStr : String;
  public
    procedure ShowHelloMessage;
  end;

procedure DoMyProc(ProcAddress : Pointer);
var
  MyProc : procedure;
begin
  MyProc := ProcAddress;
  MyProc;
end;

procedure TForm1.ShowHelloMessage;
begin
  ShowMEssage(FMsgStr);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FMsgStr:='Hallo!';
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  M : TMyMethod;
begin
  M := ShowHelloMessage;
  DoMyProc(@M);
end;



Для простоты ушел от DLL, используя локальную функцию вместо вызываемой из DLL. Ну, и еще изменил название типа с TMethod на TMyMethod, так как тип TMethod уже имеется и не хочется его переписывать.

И еще один момент. Я не уверен, что Ваш подход не рпиведет к каким-нибудь неприятностям, типа утечек памяти. Но разбираться в этом в два часа ночи уже лениво ;-)

23-01-2008 17:23
сразу говорю - чур не пЕнать, ибо я не турбопрограммер, просто вопрос заинересовал.

но почему какой Вам от этого гешефт

library MyDll;

procedure DoMyProc(ProcAddress : Pointer);
var
  MyProc : procedure;
begin
  MyProc := ProcAddress;
  MyProc;
end;

exports DoMyProc;
begin
end.





type
  TMethod = procedure of object;
  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    procedure BitBtn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    procedure ShowHelloMessage;
  end;

  procedure DoMyProc(ProcAddress : Pointer); external 'MyDll.dll';

procedure TForm1.ShowHelloMessage;
begin
ShowMEssage('Hello!');
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
var
  M : TMethod;
begin
  M := ShowHelloMessage;
  DoMyProc(@M);
end;


23-01-2008 15:56
Давайте еще раз.

Вызов процедуры и вызов метода класса -- это совершенно разные вещи. Если функция из DLL требует адрес процедуры, которую она потом будет вызывать (подозреваю, что вызывать она будет именно процедуру), то, передав ей вместо адреса процедуры адрес метода, Вы рискуете получить... даже не соображу сходу, что именно.

Так что уточните, что именно требует функция из DLL.

>>> Может я ошибаюсь, но почему то в моей голове вертятся слова "of object"
При описании процедурного типа добавление в конце "of Object" говорит, что этот тип не процедура, а метод класса.

type
  TMyProc = procedure(N : Integer); // процедура
  TMyMethod = procedure(N : Integer) of object; // метод класса


Только я в упор не понял, какой Вам от этого гешефт. Вы то сами как раз ничего не объявляете.

23-01-2008 15:43 | Сообщение от автора вопроса
Мне необходим именно указатель на метод.
Я использую чужую DLL, одна из функций которой создаёт таймер, и требует в качестве параметра
именно указатель на процедуру, которою будет вызывать по этому таймеру. Эта процедура описанна в моём классе как событие. Вот указатель на неё я и хочу получить.
Может я ошибаюсь, но почему то в моей голове вертятся слова "of object".
Не нужно ли их использовать при описании метода, адрес которого я хочу получить?

23-01-2008 15:41 | Комментарий к предыдущим ответам
Этот вопрос интересовал и Ins-а (»вопрос КС №58424«)

23-01-2008 14:08
>>> При попытке получить адрес, выскакивает ошибка: "Variable required"
А это Delphi от Вас защищается, чтобы Вы глупостей не наделали ;-) Потому что работать с методами класса просто обращаясь по адресам этих методов нельзя. Правильное обращение состоит не только из указателя на метод, но и из указателя на экземпляр класса.

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

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Два кольца, два конца, посередине гвоздик.
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования