Последние темы Поиск
Общие форумы
Специализированные форумы
ПроцессорыРазгон и охлаждениеСистемные платыМодули памятиВидеосистемаTV- и FM-тюнеры, видеовход, видеовыходЦифровое видео: захват, монтаж, обработкаМониторы и другие устройства отображенияЦифровое фотоБеспилотные летательные аппаратыЦифровой звукProAudio: Профессиональное звуковое оборудованиеСтереосистемыДомашний кинотеатр: проигрыватели и источники сигналаДомашний кинотеатр: аудиосистемаДомашний кинотеатр: ТV и проекторыМагнитные и SSD накопителиОптические носители информацииСетевые носители информацииПериферияКорпуса, блоки питания, UPSСети, сетевые технологии, подключение к интернетуСистемное администрирование, безопасностьСерверыНоутбуки, нетбуки и ультрабукиПланшеты и электронные книгиМобильные телефоны, смартфоны, кпк, коммуникаторыМобильные гаджетыОператоры и технологии мобильной связиТелефония, телекоммуникации, офисные АТСБытовая техника
Программы
Игры
Авторские форумы
Прочие форумы
Форумы поддержки портала iXBT.com
Архивы конференции
Архив "О Конференции"Архив "Процессоры"Архив "Разгон и охлаждение"Архив "Системные платы"Архив "Модули памяти"Архив "Видеосистема"Архив "Видеозахват"Архив "Мониторы и другие устройства отображения"Архив "Цифровое изображение"Архив "Цифровой звук"Архив "Периферия"Архив "Корпуса, блоки питания, UPS"Архив "Коммуникации: сети и сетевые технологии"Домашний интернет, модемы (архив)Архив "Системное администрирование, безопасность"Архив "Мобильная связь"Программы Microsoft: Windows, Office, Server, Windows LiveАрхив "OС и системное ПО"Архив "Программы: Интернет"Архив "Программирование"Форум прикладных программистовАрхив "Электронные устройства и компоненты"Архив "Околокомпьютерный Флейм & Общий"Архив "Полемика (Злобный Флейм)"Околоавтомобильный ФлеймФорум ремонтниковВопросы компании IntelФотокамеры SamsungФорум о магазине приложений RuStoreФорум по продукции компании Huawei
Справка и сервисы
Другие проекты iXBT.com
vaasyl: проблема при переводе С-шного заголовочного файла dll-ки на delphi
vaasyl
unregistered
Автор темы
Ответить
v
vaasyl unregistered Автор темы
  22 года назад / 28 марта 2003 18:31
проблема в следующем:

в с-шном файле объявлена некая структура:
typedef struct{
X:int;
Y:int;
}XYPOS;

и функция, возвращающая результат типа этой структуры:
XYPOS WINAPI SomeFunc();

соответственно при вызове функции из проекта MS Visual CPP
все работает правильно:
void main(){
XYPOS a;
a = SomeFunc();
}

при переводе всего этого на паскаль получилось:

в заголовке:
interface
type XYPOS=record
X:integer;
Y:integer;
end;
function SomeFunc():XYPOS stdcall; external 'mydll.dll' index 0001;
implementation
end.

в приложении при вызове этой функции возникает access violation:
var
a:XYPOS;
begin
a:=SomeFunc; //здесь возникает ошибка
Somefunc; //и даже здесь та же ошибка, т.е. дело не в несовместимости
// размеров переменных
end;

пробовал:
record менять на packed record - тот же результат.
интересно, что если в объявлении функции заменить XYPOS на int64 (размер у них одинаковый), то все работает без ошибок и верхним 32 битам результата присваивается XYPOS.X , а нижним XYPOS.Y.
Просмотр окна CPU показал, что в зависимости от типа возвращаемого результата (record или не record, т.е все простые типы начиная от byte и кончая pointer проходят) выполнение функции идет по двум разным путям:
В одном месте стоит call eal+$00000008 и eal может принимать два разных значения.

Может быть я чио-ио не правильно сделал? Подскажите, пжлста, что можно еще попробовать.
Розарио Агро
unregistered
Ответить
Р
Розарио Агро unregistered
22 года назад / 28 марта 2003 23:16
Вообще-то Дельфевый Integer побольше Сишного будет
smallint в дельфях в рекорде пробовал?

А тип TPoint на что, кстати? Он же юзается в куче портированных в дельфи винапишных функций.
Погляди windows.pas - там все правильно сделано
vaasyl
unregistered
Автор темы
Ответить
v
vaasyl unregistered Автор темы
22 года назад / 31 марта 2003 13:07
Пробовал и smallint и tpoint, и windows.pas изучал.
Короче, если в объявлении функции писать тип возврата любой кроме record, все работает; а если record (в том числе и tpoint), выполнение функции идет другим путем, в процессе которого возникает ошибка.
Кстати если тип возврата сделать pointer, то в него записывается не адрес результата, а сам результат (сколько поместится).
Можно было бы обойти эту проблему с помощью int64, но в этой dll-ке есть функции, возвращающие структуру и большего размера, а в delphi, на сколько я знаю, нет простых типов польше 64 бит.
Pasm
unregistered
Ответить
P
Pasm unregistered
22 года назад / 31 марта 2003 20:08
А ты уверен, что фуеция экспортируется как STDCALL?
McFirst
unregistered
Ответить
M
McFirst unregistered
  22 года назад / 01 апреля 2003 14:28
vaasyl
Сдается мне, что Pasm прав и вызов там "С"-style, а не "Pascal"-style (aka stdcall).
Заголовочный файл (его кусок с описанием импортируемой функции) "как есть" в студию.


И, в самом деле, используйте тэг code. Уважайте коллег.
Alexil
Member
479/1304 ответов
24 года на iXBT, с июня 2000
162 фото на iXBT.photo
Чаще пишет в "Фото" (27%)
Россия, Москва
Инфо Ответить
A
Alexil Member
22 года назад / 01 апреля 2003 15:18
Дело, похоже, в том, что функции, возвращающие Record, в Object Pascal реализованы тупее, чем в С - им на вход всегда (неявно) подается адрес временной стековой переменной, куда ф-ция должна записать результат, назависимо от размера рекорда. В С, судя по всему, если результат помещается в пару регистров, он в регистрах и возвращается.

Так что - посмотри отладчиком, как вызывается функция в С и Pascal и сделай выводы...

ЗЫ: Чтобы впредь не возникало таких проблем совместимости, лучше организовывать возврат данных (отличных от простых) из библиотечных ф-ций через параметры по ссылке или на худой конец нетипизированные указатели, как это делается в WinAPI...
vaasyl
unregistered
Автор темы
Ответить
v
vaasyl unregistered Автор темы
22 года назад / 02 апреля 2003 14:23
Pasm, McFirst
stdcall как раз ближе к с-style, чем к pascal-style. Разница только в том, кто удаляет параметры из стека после вызова функции: сама функция или caller (информация из справки по delphi).
Я конечно попробовал заменить stdcall на cdecl, но разницы не заметил.

MkFirst
Привожу куски файлов leicastd.h и lgmpro.h

01//----leicastd.h:
02  
03/* Force all EXEs/DLLs to use STRICT type checking. */
04#ifndef STRICT
05    #define STRICT
06#endif
07  
08#ifndef _WINDOWS_
09    #include <windows.h>
10#endif
11  
12#ifndef _INC_WINDOWSX
13    #include <windowsx.h>
14#endif
15  
16/* disable nonstandard extension 'single line comment' was used */
17#pragma warning(disable: 4001)
18  
19  
20#ifndef _LEICA_STD_
21    #define _LEICA_STD_
22#endif
23  
24/* General LEICA constants and types */
25  
26#ifndef  XYTYP
27#define  XYTYP  LONG
28typedef struct {
29  XYTYP  X;
30  XYTYP  Y;
31} XYPOS;
32#endif
33  
34#ifndef SYS_HANDLE
35#define SYS_HANDLE    VOID*
36#endif
37  
38  
39  
40//-----lgmpro.h
41  
42#ifndef _LEICA_STD_
43    #include <leicastd.h>
44#endif
45  
46/* --- function prototypes --- */
47 XYPOS  WINAPI StgGetPos (SYS_HANDLE Stg, BOOL *pbError);

Alexil
насчет организации возврата данных: эту библиотеку писал не я. Если-бы у меня был исходник, вопросов вообще бы не было.

Насчет структур больше 64 бит я погорячился, их там нет. Так-что пока обхожусь int64, разбивая его на два integer, но это, конечно не полноценное решение проблемы
McFirst
unregistered
Ответить
M
McFirst unregistered
  22 года назад / 02 апреля 2003 15:41
Alexil
Не верно.
[b

MSDN Library[/b]]
Functions declared using the __stdcall modifier return values the same way as functions declared using __cdecl.
Что же касается использования регистров, то этим управляет директива __fastcall.

vaasyl
Насчет "ближе". ВСЕ вызовы в Паскале (Дельфи, все-таки, не Паскаль, поэтому может делать и по-другому) проиходят по умолчанию в соглашении stdcall. Более того, в Паскале не существует средств смены соглашений о вызове. В С же ВСЕ вызовы происходят по умолчанию, наоборот, в соглашении cdecl.
Кроме того, в этих соглашениях по-разному декорируются экспортируемые имена (в stdcall префиксится с "_" и завершается @NN, где NN - это суммарный размер параметров в байтах, а в cdecl - просто префиксится "_"; а вот что делает C++ - это надо видеть!).

Вот, кстати, еще идея пришла: посмотри каким-нибудь доступным инструментом, как на самом деле экспортируется функция (в VC есть dumpbin, позволяющий с ключем /exports просматривать список экспортированных функций). Правда, если экспорт был прописан в exp-файле, то ты, скорее всего, увидишь только имя функции...

WINAPI, кстати,- это stdcall...

Кто грузит библиотеку (DLL) в Delphi и в VC?



Кстати, а что за регистр eal? Есть eax. В котором два слова, нижнее из которых обозначается ax, которое в свою очередь состоит из двух байт al и ah (от англ. low и high). Разве только по аналогии с байтами слова обозначаются (eal (aka ax) и eah). Но я такого не видел...



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


Не иначе библиотека от цифровой камеры... А с ихним саппортом связаться не пробовал?


За использование тэгов - спасибо.
Alexil
Member
481/1312 ответов
24 года на iXBT, с июня 2000
162 фото на iXBT.photo
Чаще пишет в "Фото" (27%)
Россия, Москва
Инфо Ответить
A
Alexil Member
22 года назад / 02 апреля 2003 15:48
McFirst
Вы не совсем правы, сэр
ВСЕ вызовы в Паскале (Дельфи, все-таки, не Паскаль, поэтому может делать и по-другому) проиходят по умолчанию в соглашении stdcall. Более того, в Паскале не существует средств смены соглашений о вызове.
В Delphi (32-bit) ВСЕ вызовы по умолчанию - fastcall (т.е. все что можно передается через регистры)
Средства управления соглашениями о вызове тоже есть (fastcall, stdcall, cdecl, safecall)
И это все имеет отношение только к ПЕРЕДАЧЕ ПЕРАМЕТРОВ, а никак не к ВОЗВРАТУ ЗНАЧЕНИЯ ФУНКЦИЕЙ. Так вот, повторяю, в Pascal (Delphi) все функции, возвращающие значения типа Record, делают это через временную переменную, в С похоже это не так.

PS: Был малость не прав... Оказывается, если Record помещается в AL/AX/EAX, то возвращается в регистре, иначе через временную переменную. В данном случае в один регистр не лезет...

Исправлено: Alexil, 02.04.2003 17:22

vaasyl
unregistered
Автор темы
Ответить
v
vaasyl unregistered Автор темы
22 года назад / 02 апреля 2003 17:13
MсFirst
Ну, я сужу только по справке delphi:
1Directive   Parameter order Clean-up     Passes parameters in registers?
2  
3register    Left-to-right   Routine     Yes
4pascal  Left-to-right   Routine     No
5cdecl   Right-to-left   Caller      No
6stdcall Right-to-left   Routine     No
7safecall    Right-to-left   Routine     No
dumpbin выдает только имя, индекс, hint и точку входа.

Кто грузит библиотеку (DLL) в Delphi и в VC?
В смысле?

На счет регистра - написал от балды. Вот как на самом деле:
1call dword ptr [esi + $00003d8]
Не иначе библиотека от цифровой камеры... А с ихним саппортом связаться не пробовал?
Библиотека от моторизированного микроскопа. А что я у них спрошу? Скажут "пиши на С".
Jon Braun
unregistered
Ответить
J
Jon Braun unregistered
22 года назад / 02 апреля 2003 19:46
Правильно ли я понял, что Вы перевели на Pascal и приложение и DLL?

Добавление от 02.04.2003 20:03:

Нет времени более сидеть перед машиной. Если на мой вопрос ответ положительный, то учтите следующие ньюансы.

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

2. Если это не поможет, то попробуйте явно загружать библиотеку DLL с помощью функции LoadLibrary()

Более подробно, если хотите, напишу в Пятницу.
McFirst
unregistered
Ответить
M
McFirst unregistered
  22 года назад / 02 апреля 2003 20:14
Alexil
vaasyl
Да, с соглашениями о вызове сильно напутал.

vaasyl

Кто грузит библиотеку (DLL) в Delphi и в VC?

В смысле?
Ну, есть lib к ней? Или LoadLibrary ручками? Или в Дельфи, если сказать external 'mydll.dll' index 0001;, то все происходит само?

Добавление от 02.04.2003 20:18:

Alexil
Что касается возвращаемых значений: неужели нет никакой возможности ЯВНО указать, как надо возвращать? Это ж беспредел получается...
Кстати, Ваши выводы - это результаты эксперимента?


P.S. Говорил же я: Дельфи - не Паскаль!
Alexil
Member
484/1315 ответов
24 года на iXBT, с июня 2000
162 фото на iXBT.photo
Чаще пишет в "Фото" (27%)
Россия, Москва
Инфо Ответить
A
Alexil Member
22 года назад / 03 апреля 2003 07:05
McFirst
В Delphi точно нельзя управлять тем, как ф-ция должна возвращать результат. В С скорее всего тоже (эксперты поправят, если наврал).
Выводы частично из Help-а по Delphi, а насчет данного конкретного случая - эксперимент подтвердил мои предположения, С-шная функция (VC6) действительно возвращает результат в EDX/EAX, а Delphi полагает, что результат должен возвращаться во временной переменной, адрес которой она в виде неявного параметра PUSH-ает в стек перед вызовом. Естественно, там оказывается не то, что она ожидает... Да и лишний DWORD остается в стеке...
vaasyl
unregistered
Автор темы
Ответить
v
vaasyl unregistered Автор темы
22 года назад / 04 апреля 2003 15:42
Jon Braun
Если имеется в виду приложение и заголовочный файл к DLL, то - да. Как можно перевести саму DLL, я не представляю.
Пробовал добавлять sharemem - результат тот же.

McFirst
Да lib прилагался, но на сколько я понял, это то-же самое, что и dcu в delphi. То есть в оригинале на С вызов статический (или я ошибаюсь?).

Jon Braun, McFirst
Мне бы ОЧЕНЬ не хотелось переходить на динамическую загрузку (loadlibrary), т.к. я слышал, что это более глючный метод, да и переделывать придется очень много. Но чувствую, что придется попробывать.

Alexil
В том то и дело, что до возврата результата дело не доходит - ошибка возникает где-то в теле функции.

Кстати, интернет у меня на работе, а там я появляюсь не каждый день. Так-что уж извините, если не сразу реагирую на ответы. Следующий раз, естественно, буду в понедельник.
Tor Bel
unregistered
Ответить
T
Tor Bel unregistered
22 года назад / 04 апреля 2003 17:22
Может быть имеет смысла поиграть флажком - Свойства проекта -> Компиляция -> Выравнивание полей записи 32бит?
Gipnoss
Member
530/629 ответов
24 года на iXBT, с декабря 2000
5 фото на iXBT.photo
Чаще пишет в "Политика" (45%)
Украина, Харьков
Web-страница
Инфо Ответить
Gipnoss Member
22 года назад / 05 апреля 2003 03:01
Глупая мысль - а если объявить как :
procedure SomeFunc(XYPOS_var:XYPOS) stdcall; external 'mydll.dll' index 0001;
Или что-то вроде этого?

Добавление от 05.04.2003 03:51:

Действительно глупая........ничего не изменится от этого.....

Ага...вот что хэлп думает по этому поводу:
Delphi Language Reference

The following conventions are used for returning function result values.

*Ordinal results are returned, when possible, in a CPU register. Bytes are returned in AL, words are returned in AX, and double-words are returned in EAX.
*Real results are returned in the floating-point coprocessor's top-of-stack register (ST(0)). For function results of type Currency, the value in ST(0) is scaled by 10000. For example, the Currency value 1.234 is returned in ST(0) as 12340.
*For a string, dynamic array, method pointer, or variant result, the effects are the same as if the function result were declared as an additional var parameter following the declared parameters. In other words, the caller passes an additional 32-bit pointer that points to a variable in which to return the function result.
*Int64 is returned in EDX:EAX.
*Pointer, class, class-reference, and procedure-pointer results are returned in EAX.
*For static-array, record, and set results, if the value occupies one byte it is returned in AL; if the value occupies two bytes it is returned in AX; and if the value occupies four bytes it is returned in EAX. Otherwise, the result is returned in an additional var parameter that is passed to the function after the declared parameters.
Почему C кладет такой результат в EDX:EAX, а Делфи об этом ничего не знают - сложный вопрос, но факт остается фактом.
А для структур больше int 64 по идее оно в регистры должно не влезть и передаваться через ссылку в стеке, надеюсь С так и делает....
Kid_Deceiver
Moderator
4556/4687 ответов
25 лет на iXBT, с декабря 1999
Чаще пишет в "Программирование" (94%)
Инфо Ответить
K
Kid_Deceiver Moderator
22 года назад / 05 апреля 2003 06:45
vaasyl
Мне бы ОЧЕНЬ не хотелось переходить на динамическую загрузку (loadlibrary), т.к. я слышал, что это более глючный метод,
Вы слышали снеправильно. LoadLibrary в целом (по устойчивости) абсолютно эквивалентен стандартному DLL later binding (т.к. загрузчик de facto вызывает тоже LoadLibrary). Но явный LoadLibrary удобнее тем, что он гибче, т.е. позволяет учитывать в программе результаты загрузки, подменять одну DLL другой и т.д. Тогда как обычное связывание, при к.-л. проблемах с DLL кончается тем, что application просто не стартует.

Платить за это удобство приходится немножко большим количеством кода.
psnsergey
Member
65/120 ответов
22 года на iXBT, с июля 2002
Чаще пишет в "Политика" (47%)
Россия, Москва
Инфо Ответить
psnsergey Member
22 года назад / 05 апреля 2003 19:35
Есть идея. Напиши на Дельфи заглушку (у меня это Horror), которая будет вызываться из нормального объявления функции, давая ей результат. Типа такого:
01function Usable: ReturnType; //для себя
02var Tmp: Int64;
03begin
04  Tmp:=Horror;
05  Result.Par1:= {блаблабла из Tmp};
06  Result.Par2:= {блаблабла из Tmp};
07end;
08  
09// для компилятора.
10function Horror: Int64; external...... stdcall:
Немного через ж..., но должно работать. Если важна скорость, юзай Horror и касти каждый раз результат типа Int64 прямо в твою запись (разумеется, выровненную по 4-байтовой границе).

Исправлено: psnsergey, 05.04.2003 19:59

vaasyl
unregistered
Автор темы
Ответить
v
vaasyl unregistered Автор темы
22 года назад / 07 апреля 2003 16:01
Попробовал я вызывать через loadlibrary. Вот заголовочный модуль, сгенерированный программой HeadConv 4.20 (отредактированный):
01unit dm_lgm.pas;
02interface
03uses windows;
04  
05type
06  SYS_HANDLE=pointer;
07  XYTYP=longint;
08  XYPOS=record
09    X:XYTYP;
10    Y:XYTYP;
11  end;
12  
13var
14  StgGetPos:function (Stg: SYS_HANDLE;
15                   var pbError: Bool): XYPOS {$IFDEF WIN32} stdcall {$ENDIF};
16  
17  DLLLoaded: Boolean { is DLL (dynamically) loaded already? }
18    {$IFDEF WIN32} = False; {$ENDIF}
19  
20implementation
21var
22  SaveExit: pointer;
23  DLLHandle: THandle;
24{$IFNDEF MSDOS}
25  ErrorMode: Integer;
26{$ENDIF}
27  
28  procedure NewExit; far;
29  begin
30    ExitProc := SaveExit;
31    FreeLibrary(DLLHandle)
32  end {NewExit};
33  
34procedure LoadDLL;
35begin
36  if DLLLoaded then Exit;
37{$IFNDEF MSDOS}
38  ErrorMode := SetErrorMode($8000{SEM_NoOpenFileErrorBox});
39{$ENDIF}
40  DLLHandle := LoadLibrary('DM_LGM.DLL');
41  if DLLHandle >= 32 then
42  begin
43    DLLLoaded := True;
44    SaveExit := ExitProc;
45    ExitProc := @NewExit;
46    @StgGetPos := GetProcAddress(DLLHandle,'StgGetPos');
47  {$IFDEF WIN32}
48    Assert(@StgGetPos <> nil);
49  {$ENDIF}
50  end
51  else
52  begin
53    DLLLoaded := False;
54    { Error: DM_LGM.DLL could not be loaded !! }
55  end;
56{$IFNDEF MSDOS}
57  SetErrorMode(ErrorMode)
58{$ENDIF}
59end {LoadDLL};
60  
61begin
62  LoadDLL;
63end.
Так вот теперь выдается ошибка access violation at adress 00000001. Причем возникает она после следующего:
1call dword ptr [esi + $00003d8]
Здесь esi + $00003d8 далеко не 00000001, но переход осуществляется именно на 00000001.

Tor Bel
Нет, это ничего не дает

Gipnoss
Действительно, при объявлении возвращаемого результата как int64 происходит следующее:
1mov [pos64],eax
2mov [pos64+$4],edx
А если record, то:
1mov eax,[ebp-$54]
2mov [pos],eax
3mov eax,[ebp-$50]
4mov [pos+$4],eax
Но до этого, как я уже говорил, дело не доходит.

Kid_Deceiver
Почему тогда поставляемые с delphi заголовки (например windows.pas) не используют loadlibrary?

psnsergey
что-то я не очень понял. Ты имеешь в виду включить функцию horror в dll? Но у меня нет исходника dll. Я делаю так:
1var
2  pos:XYPOS;
3function i64p(i:int64):XYPOS;
4begin
5  result.x:=(i and $00000000FFFFFFFF);
6  result.y:=(i and $FFFFFFFF00000000)shr 32;
7end;
8//
9pos:=i64p(StgGetPos (Stg, bError));
Еще, можно поподробней, как это - кастить?
psnsergey
Member
72/127 ответов
22 года на iXBT, с июля 2002
Чаще пишет в "Политика" (47%)
Россия, Москва
Инфо Ответить
psnsergey Member
22 года назад / 07 апреля 2003 19:53
Не экспериментируй с loadLibrary - железно собака зарыта не там.
Ты в своей проге объявляешь - дескать, в ДЛЛ есть такая-то приблуда stdcall. Но Дельфи считает, что этой приблуде надо давать var-параметр чтоб она туда кидала результирующую запись. А приблуда упрямо ложит запись в два регистра. Но Дельфи тоже поддерживает такой возврат в регистрах - ДЛЯ INT64. То есть надо немного обмануть ДЛЛ (в ней сохраняется только инфа о именах, не о типах принимаемых/возывращвемых значений.) Ты объявляешь подставную функцию с Result как Int64. И потом можно так: Переменная_типа_записи:= Тип_записи(Вызов_Функции). То есть Int64 становится записью.
1var R: MyRecord;
2R:= MyRecord(Horror); // УРА!!! Кастим в наш тип. (cast)
Всё это заключается в "дружественный" тулуп "function Usable". Но дополнительный вызов функции - это (хотя и небольшое) время. Так что можно каждый раз кастить (MyRecord(...)), а можно через тулуп.
vaasyl
unregistered
Автор темы
Ответить
v
vaasyl unregistered Автор темы
22 года назад / 10 апреля 2003 13:26
psnsergey
Вот теперь понял, что значит кастить. Спасибо. И как это я сам не догадался? И если это через ж..., то через что же тогда я делал до этого?
Ваш ответ:

Нет значка Нет значка Вот тут! Лампочка Восклицание Вопрос Класс! Улыбка Злость Огорчение Поговорим? Краснею Подмигивание Ругаю ОдобряюBIUdelSxsupxsuboffsp spoilerqurlimgvideo• list1. list1 codeprecenter-hr-rusQWE→ЙЦУ
файлыочистить
Ваше имя: Авторизуйтесь Предпросмотр В полную форму
вставить выделенную цитату в окно ответа
Если Вы считаете это сообщение ценным для дискуссии (не обязательно с ним соглашаться), Вы можете поблагодарить его автора, а также перечислить ему на счет некоторую сумму со своего баланса (при отзыве благодарности перечисленная сумма не будет вам возвращена).
Также вы можете оценить сообщение как неудачное.
В течение суток можно 20 раз оценить сообщения разных участников (купите Premium-аккаунт, либо оплачивайте оценки сверх лимита).
Если Вы считаете это сообщение ценным для дискуссии (не обязательно с ним соглашаться), Вы можете поблагодарить его автора, а также перечислить ему на счет некоторую сумму со своего баланса (при отзыве благодарности перечисленная сумма не будет вам возвращена).
Также вы можете оценить сообщение как неудачное.
В течение суток можно 20 раз оценить сообщения разных участников (купите Premium-аккаунт, либо оплачивайте оценки сверх лимита).