Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2003.06.02;
Скачать: [xml.tar.bz2];

Вниз

Передача указателя на функцию   Найти похожие ветки 

 
Top Gun   (2003-05-11 14:32) [0]

У меня есть класс, там в private объявлена функция

function WndProc(Hwn:HWND; Msg,wpr,lpr:cardinal):cardinal;stdcall;

Если я в одном из методов класса пишу:

WindowClass.lpfnWndProc := @(wndproc);

То компилятор сообщает [Error] QuickWinApi.pas(67): Not enough actual parameters

Но мне не нужно вызывать функцию, мне нужно записать в WindowClass.lpfnWndProc ее адрес !


 
Ihor Osov'yak   (2003-05-11 14:40) [1]

:= @(ИмяКласса.WndProc);


 
PVOzerski   (2003-05-11 14:59) [2]

Только вот использовать метод класса как API-шный callback для окна нельзя, так как помимо перечисленных Вами, метод имеет неявный параметр-ссылку на экземпляр класса. Между прочим, процедурные переменные для методов (напр., procedure of object, tNotifyEvent и т.п.) состоят фактически из двух указателей - на код и на данные. Так что, если я правильно понял то, что Вы хотите сделать, пересмотрите подход. В VCL, например, сообщения обрабатываются через PeekMessage, а callback"ом работает DefWindowProc. Я, в свое время, хаживал и другим путем: прицеплял через SetWindowLong к окошку указатель на экземпляр класса и делал свой универсальный callback для всех окон программы, который вызывал методы-обработчики, добираясь до них через GetWindowLong. А вообще, в VCL у форм есть и свой переопределяемый метод WndProc, которым пользоваться достаточно удобно.


 
Top Gun   (2003-05-11 15:01) [3]

Ничего не понимаю. Так ведь функция WndProc у меня реализована
в моем классе. А если будет несколько экземпляров класса, то...

Давайте добавлю код, чтобы стало более понятно:


TMyClass = class
private
WindowClass: TWNDClass;
function WndProc(Hwn:HWND;Msg,wpr,lpr:cardinal):cardinal;stdcall;
constructor create;
end;

.....

constructor TMyClass.create
WindowClass.lpfnWndProc := @(wndproc) ;//Not enough actual parameters
end;


Теперь надеюсь понятно. То есть, в каждом экземпляре TMyCLass есть WindowClass, в свойстве lpfnWndProc которого должен быть записан адрес на функцию wndproc именно этого класса, а не TMyClass.wndproc


 
PVOzerski   (2003-05-11 15:17) [4]

А Вы что, полагаете, что каждый экземпляр класса имеет свою копию кода для методов?


 
Ihor Osov'yak   (2003-05-11 15:24) [5]

2 PVOzerski © (11.05.03 14:59)

так ведь вопрос был об ошибке синтаксиса. И предполагалось наличие встречного вопроса, типа "а мне нужно не класс вообще, а мой екземпляр" :-)


2 Top Gun (11.05.03 15:01)

Все методы класса получают неявный параметр-указатель на екземпляр класса. Поэтому их нельзя использавать как системные call-back - см. PVOzerski ©





 
Top Gun   (2003-05-11 16:25) [6]

Все, понял, что вы имеете в виду. Тогда сделаю так: объявлю функцию wndproc универсальную для каждого экземпляра, а при ее вызове уже буду определять к какому экземпляру относится данное сообщение по параметру Hwn. Верно ? Можно так ?


 
Ihor Osov'yak   (2003-05-11 17:02) [7]

wndproc как процедура окна не может быть методом класса.

Как это обходить? Посмотрите хотя бы на
procedure TWinControl.CreateWnd;
function InitWndProc(HWindow: HWnd; Message, WParam: Longint;
LParam: Longint): Longint; stdcall; в модуле controls;

Способов есть много - поищите на поисковиках что-то типа Delphi without VCL, посмотрите также исходники KOL - там также этот вопрос решен и наверное несколько иначе, чем в VCL..

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


Еще раз - исходники unit controls, и особое внимание на использование
WindowAtom, ControlAtom ... Над каждым случаем использования думать долго, до полного просветления.




 
Top Gun   (2003-05-12 18:36) [8]

через SetProp привязываем к виндозному окну указатель на свой екземпляр.. Не забудьте потом только о RemoveProp..

Ничего не понял :-(

Я вот все пытался разобраться - не помогает. Меня, наверное, уже ничего не спасет, кроме ваших мудрых советов. В VCL тоже смотрел - тоже не понял

Давайте повторю, что я бы хотел:

Есть класс:

TMyClass = class
private
WindowClass: TWNDClass;
Handle:hwnd;
constructor Create;
end;

В нем содержится класс окна WindowClass и сам handle созданного окна (окно создается в конструкторе TMyClass.Create). Соответственно хочется, чтобы каждый экземпляр класса обрабатывал сообщения своего окна. Конечно, можно написать одну функцию wndproc, которая будет обрабатывать сообщения окон всех экземпляров TMyClass. Но вот в чем беда. В ответ на определенные сообщения класс генерирует события. И если функция wndproc едина, как определять к какому окну какого экземпляра класса TMyClass пришло сообщение и в каком экземпляре генерировать событие ? Вот такая беда у меня !

Если можно - поподробнее, идеально - с примерами! Только не отфутболивайте, очень нужно !

Заранее спасибо!


 
Skier   (2003-05-12 18:42) [9]

>Top Gun (12.05.03 18:36)
посмотри тип TWndMethod Не спасёт ?


 
Serginio   (2003-05-12 18:49) [10]

Есть очень хорошая функция Помоему MakeObjectInstance которая создает код функции для обращения к функции конкретного экземпляра класса.


 
Serginio   (2003-05-12 18:55) [11]

unit Classes;
function MakeObjectInstance(Method: TWndMethod): Pointer;
const
BlockCode: array[1..2] of Byte = (
$59, { POP ECX }
$E9); { JMP StdWndProc }
PageSize = 4096;
var
Block: PInstanceBlock;
Instance: PObjectInstance;
begin
if InstFreeList = nil then
begin
Block := VirtualAlloc(nil, PageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Block^.Next := InstBlockList;
Move(BlockCode, Block^.Code, SizeOf(BlockCode));
Block^.WndProcPtr := Pointer(CalcJmpOffset(@Block^.Code[2], @StdWndProc));
Instance := @Block^.Instances;
repeat
Instance^.Code := $E8; { CALL NEAR PTR Offset }
Instance^.Offset := CalcJmpOffset(Instance, @Block^.Code);
Instance^.Next := InstFreeList;
InstFreeList := Instance;
Inc(Longint(Instance), SizeOf(TObjectInstance));
until Longint(Instance) - Longint(Block) >= SizeOf(TInstanceBlock);
InstBlockList := Block;
end;
Result := InstFreeList;
Instance := InstFreeList;
InstFreeList := Instance^.Next;
Instance^.Method := Method;
end;

{ Free an object instance }

procedure FreeObjectInstance(ObjectInstance: Pointer);
begin
if ObjectInstance <> nil then
begin
PObjectInstance(ObjectInstance)^.Next := InstFreeList;
InstFreeList := ObjectInstance;
end;
end;


 
&#28010;&#20154;   (2003-05-12 19:12) [12]

Оконная процедура по умолчанию, получаемая из метода
TWinControl.MainWndProc с помощью MakeObjectInstance,
вызывает метод, хранящийся в свойстве
TControl.WindowProc
(тип - TWndMethod = procedure(var Message: TMessage) of object)

procedure TWinControl.MainWndProc(var Message: TMessage);
begin
try
try
WindowProc(Message);
finally
FreeDeviceContexts;
FreeMemoryContexts;
end;
except
Application.HandleException(Self);
end;
end;


И имеет смысл не менять оконную процедуру, а поменять
это свойство.
Во-первых, поскольку оно именно с этой целью и сделано,
а во-вторых, в некоторых случаях оно вызывается напрямую, а не через оконную процедуру (например, при вызове Perform).


 
Serginio   (2003-05-12 19:29) [13]

При использовании MakeObjectInstance желательно получить старый обработчик окна через GetWindowLong и вызывать его в новом обработчике.


 
Top Gun   (2003-05-21 00:05) [14]

Ничего не понимаю :-(

У меня нету TWinControl !

Я сделал так:

type
TWndProc=function (Hwn:HWND; Msg,wpr,lpr:cardinal):cardinal;stdcall;
...

В классе объявил поле типа TWndProc:
WndProc:TWndProc;

В конструкторе класса пишу:

WindowClass.lpfnWndProc := @(wndproc) ;

Все равно при этом предупреждение:

"Not enough actual parameters"

Если объявлять

TWndProc=function (Hwn:HWND; Msg,wpr,lpr:cardinal):cardinal of object;stdcall;

Тоже самое. А кстати, чем будет отличаться такие объявление. Of object и без него ? Поле WndProc:TWndProc; все равно могу объявить.

Объясните поподробнее! Как можно справиться с моей проблемой, если кто что понял...


 
Ihor Osov'yak   (2003-05-21 00:42) [15]

> Как можно справиться с моей проблемой

почитать не спеша и вдумчиво книжки. Для начала те, кде хорошо описан синтаксис.. В том числе, и работа с процедурными типами, указателями, в тч. на методы, процедуры и функции ..

И не лесть поначалу в такие дебри (поверь, дебри - это поначалу.. Если книжки читать будешь, и бужешь думать - то просветление настанет..)..

Говорят, Марк Кенту хорошие понаписывал...

По существу:

> У меня нету TWinControl

unit Controls;


>WndProc:TWndProc;

В конструкторе класса пишу:

WindowClass.lpfnWndProc := @(wndproc) ;


Ты эта, не делай так.. Здесь под wndproc подразумевается вызов процедуры.. А она параметров хочет..
Должно быть WindowClass.lpfnWndProc := @Здесь_должен_быть_идентификатор_процедуры

> TWndProc=function (Hwn:HWND; Msg,wpr,lpr:cardinal):cardinal of object;stdcall;

Эта декларация не соотв. спецификации оконной процедуры...

>А кстати, чем будет отличаться такие объявление. Of object и без него ?

Насколько я помню, тебе уже это обьясняли. RTFM, одним словом..












 
Top Gun   (2003-05-21 11:06) [16]

Говорят, Марк Кенту хорошие понаписывал...

Фигню он написал, по моему (Тейксера и Пачеко намного лучше). Есть его книга - если скажешь в каком параграфе описана моя проблема, обязательно прочитаю.

> У меня нету TWinControl

unit Controls;


Это понятно. Только не могу я доп. модули подключать. Не могу и все. Задача такая.

WindowClass.lpfnWndProc := @(wndproc) ;


Ты эта, не делай так.. Здесь под wndproc подразумевается вызов процедуры.. А она параметров хочет..
Должно быть WindowClass.lpfnWndProc := @Здесь_должен_быть_идентификатор_процедуры


Блин. И что тогда вызовется, если я напишу WindowClass.lpfnWndProc := TWndProc ?!

Мне же нужно, чтобы в каждом экземпляре объекта существовал WindowClass и его свойство lpfnWndProc указывало на процедуру WndProc. Но не на общую WndProc, а на каждую для своего экземпляра.

И вот ты говоришь, что WindowClass.lpfnWndProc := @Здесь_должен_быть_идентификатор_процедуры. А почему когда я пишу прям в dpr файл (чистый WinApi), объявляю там просто функцию WndProc и класс WindowClass:TWndClass. А потом в теле главной функции пишу WindowClass.lpfnWndProc:=WndProc все проходит на ура ?

Насколько я помню, тебе уже это обьясняли. RTFM, одним словом..

Не объясняли...


 
Top Gun   (2003-05-21 11:07) [17]

Давайте объясню по другому. Более жизненно. Особенно тем, кто не работал с окнами через WinApi.

Когда создаешь окно функцией CreateWindow нужно указать класс окна. Этот класс сначала надо зарегистрировать в системе функцей RegisterClass, которой в качестве параметра передается структура TWNDCLASS. Одно из полей этой структуры lpfnWndProc указывает на функцию, которая будет обрабатывать все сообщения, приходящие окну данного класса. Например:

var WindowClass:TWndClass;
...
function WndProc(Hwn:HWND; Msg:longworc; wpr:longword; lpr:longint):longword; stdcall;
Begin
//обработка событий окна
End;

BEGIN
WindowClass.lpfnWndProc:=@WndProc;
WindowClass.lpszClassName:="TMyForm";
//Дальнейшее заполнение структуры WindowClass
RegisterClass(WindowClass);
Createwindow("TMyForm",......);
END;

Все работает на ура. Почему-то здесь, когда пишешь WindowClass.lpfnWndProc:=@WndProc никто никаких параметров не требует.

Я хочу оформить каждое окно в класс. Что-то типа того:

TMyForm=class
Handle:HWND;
WindowClass: TWNDClass;
function WndProc(Hwn:HWND;Msg,wpr,lpr:cardinal):cardinal;stdcall;
constructor create;
end;
.....
constructor TMyForm.create;
begin
WindowClass.lpfnWndProc:=@WndProc; //ОШИБКА !
WindowClass.lpszClassName:="TMyForm";
//Дальнейшее заполнение структуры WindowClass
RegisterClass(WindowClass);
Handle:=Createwindow("TMyForm",......);
end;

Таким образом я могу обрабатывать сообщения, приходящие к моему окну:

function TMyForm.WndProc(Hwn:HWND;Msg,wpr,lpr:cardinal):cardinal;stdcall;
begin
beep;
end;

В таком контексте каждый раз, когда окну придет сообщение - будет звучать звуковой сигнал. Все хорошо, но:

WindowClass.lpfnWndProc:=@WndProc; //ОШИБКА !

Хотя в примере выше, когда все пишется без класса TMyForm все ок.

Можно конечно написать общую функцию WndProc (не как метод класса). И для всех окон назначать главной функцией ее. Но это в простейшем случае. Допустим, у класса есть флаг FlagBeep в зависимости от которого надо или подавать сигнал или нет. Было бы так:

TMyForm.WndProc(Hwn:HWND;Msg,wpr,lpr:cardinal):cardinal;stdcall;
begin
if FlagBeep then beep;
end;

Но так ведб нельзя и если функция будет общая:

function ndProc(Hwn:HWND;Msg,wpr,lpr:cardinal):cardinal;stdcall;
begin
if FlagBeep then beep;
end;

Так писать нельзя. Надо как-то по Hwn найти экземпляр класса, где есть это окно, потом прочитать его FlagBeep... и тогда уж действовать. Конечно, так можно... Но есть же методу полегкче ?

P.S. VCL я читал, но мало что понял :(


 
Ihor Osov'yak   (2003-05-21 12:01) [18]

2 Top Gun (21.05.03 11:06)

>> Говорят, Марк Кенту хорошие понаписывал...
>Фигню он написал, по моему

Ню-ню...

>>unit Controls;

>Это понятно. Только не могу я доп. модули подключать.

Тебе не единыжды и русским языком говорили - смотри туда как на один из вариантов решения.. Тебе еще как сказать? По-українськи? English? Или на русском, но "канкретна"?

>Должно быть WindowClass.lpfnWndProc := @Здесь_должен_быть_идентификатор_процедуры

>Блин. И что тогда вызовется, если я напишу WindowClass.lpfnWndProc := TWndProc ?!


Ты что, читать не умеешь? Написано ведь Здесь_должен_быть_идентификатор_процедуры а не Здесь_должен_быть_идентификатор_типа. Это разные вещи. Одним словом - Кенту в зубы и от первой страницы до последней три раза. С воспитательной целью.. Количество попыток желательно увеличить, если просветления не настанет..


>Мне же нужно, чтобы в каждом экземпляре объекта существовал WindowClass и его свойство lpfnWndProc указывало на процедуру WndProc. Но не на общую WndProc, а на каждую для своего экземпляра.

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


>И вот ты говоришь, что WindowClass.lpfnWndProc := @Здесь_должен_быть_идентификатор_процедуры. А почему когда я пишу прям в dpr файл (чистый WinApi), объявляю там просто функцию WndProc и класс WindowClass:TWndClass. А потом в теле главной функции пишу WindowClass.lpfnWndProc:=WndProc все проходит на ура ?

Пожалуйста, полные фрагменты кода. Или ходя бы полные декларации. Я не телепат.. Но, впрочем, смотри ниже. Есть соображения и на эту тему..


> Не объясняли...

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

> Давайте объясню по другому. Более жизненно. Особенно тем, кто не работал с окнами через WinApi.

не нарывайси... <Xxxxxxx xxxxxxx xxxxxxxxx xxxxxxxx xxxxxx!!!>. Ты имеешь шансы быть следующим.


> Я хочу оформить каждое окно в класс. Что-то типа того:

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

> Но есть же методу полегкче ?

Лично я тебе уже третий раз повторяю - смотри исходники vcl. Там это сделано довольно изящно и просто..

> P.S. VCL я читал, но мало что понял :(

Так может и с этого начнем?

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






 
rounin   (2003-05-21 13:00) [19]

2Top Gun
Если ты не можешь пользоваться модулем Forms,
то MakeObjectInstance для тебя недоступен.

Тогда ты можешь воспользоваться таким нехитрым приёмом:

function MyGlobalWindowProc(hWnd: HWND; Msg: UINT; wParam: WPARAM;
lParam: LPARAM): LRESULT; stdcall;
// Только для потомков класса TMyClass !!!
var
Instance: TMyClass;
Message: TMessage;
begin
Longint(Instance) := GetWindowLong(hWnd, GWL_USERDATA);
// Получаем указатель на экземпляр TMyClass

// !!! Когда экземпляр TMyClass создаст окно,
// он должен в GWL_USERDATA окна положить указатель на себя.
// Недостаток такого подхода в том, что пользователь класса
// всегда может поменять данные, хранящиеся в GWL_USERDATA,
// что приведёт, естественно, к фатальным результата :-(

Message.Msg := Msg;
Message.WParam := wParam;
Message.LParam := lParam;

Instance.WndProc(Message);
Result := Message.Result;
// Вызывается виртуальный метод класса TMyClass,
// который будет производить реальную обработку событий.
end;


 
Ihor Osov'yak   (2003-05-21 13:09) [20]

> // !!! Когда экземпляр TMyClass создаст окно,
// он должен в GWL_USERDATA окна положить указатель на себя.
// Недостаток такого подхода в том, что пользователь класса
// всегда может поменять данные, хранящиеся в GWL_USERDATA,
// что приведёт, естественно, к фатальным результата :-(


Вот-вот.. И это обстоятельство, имхо достаточно для того, чтобы такой техникой не пользоваться. Имхо..


Ну народ, говорили же - смотрите vcl в части использования WindowAtom, ControlAtom (unit Controls) как на источних вдохновения и идей. Ну вряд-ли чего лучше придумаете..




 
Digitman   (2003-05-21 13:45) [21]


> Top Gun


ты сходи в модуль Forms и посмотри внимательно, как реализована ф-ция AllocateHWnd(метод_класса)

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


 
Top Gun   (2003-05-21 14:25) [22]

Парадокс то в том, что код приведенный тобой, ошибки компиляции, в указаном тобой месте не вызывает

А у меня вызывает. Именно в том месте и именно в такой формулировке. Компилирую в D7

И еще. Уважаемый, Ihor Osov"yak, не отвечайте больше в эту ветку, хорошо ? Кроме оскорблений и уничижений я ничего не увидел. Не будем развязывать войну, просто игнорируйте, пожалуйста!

rounin и Digitman, спасибо ! Попробую покопаться


 
VMcL   (2003-05-21 14:29) [23]

>Top Gun (11.05.03 14:32)

Дополнение к >Digitman © (21.05.03 13:45)

Только не забудь DeallocateHWnd в конце сделать.


 
VMcL   (2003-05-21 14:42) [24]

>Top Gun (21.05.03 14:25)

Почему не указал версию Delphi, когда вопрос постил в форум?


 
Ihor Osov'yak   (2003-05-21 14:46) [25]

2 Кроме оскорблений и уничижений я ничего не увидел.

А зря. Мне Вас искренне жаль.


 
Top Gun   (2003-05-21 17:46) [26]

Еще одно оскорбление. Скажите еще что-нибудь. Хорошо получается


 
Palladin   (2003-05-21 18:00) [27]

А я скажу свою любимую, нефиг на третий этаж через окно лезти...


 
Top Gun   (2003-05-21 18:17) [28]

Digitman, посмотрел на AllocateHWnd. Но к сожалению, не могу использовать MakeObjectInstance, так как Classes не подключен. А по коду MakeObjectInstance не понял, что она делает, чтобы реализовать аналог у себя...

Пока копаюсь над постом rounin


 
VMcL   (2003-05-21 18:37) [29]

>Top Gun (21.05.03 18:17)

А скозлить эти процедуры/функции в свой модуль религия не позволяет?


 
Top Gun   (2003-05-21 18:49) [30]

rounin, гениально! Лично для меня :-) Пока так и сделаю.


А в VCL так и сделано ? Исходники у меня есть, но я их плохо понимаю. Можете в двух словах рассказать, каким образом в VCL реализована моя проблема ? Схема действий в общем, в общих словах.


 
rounin   (2003-05-21 19:47) [31]

2Top Gun

В VCL это сделано довольно хакерским методом.
Грубо говоря, насколько я понимаю
там выделяется блок памяти с флагом исполняемого кода
и в ней формируется много тел маленьких функций с
прошитым в ней указателем на объект - на каждый экземпляр
своя процедура (точнее, не ф-й, а thunk"ов, которые пихают в регистр указатель на метод (TMethod) и прыгают на глобальную
ф-ю, которая этот метод вызывает).
Но я тоже особенно не вникал во все тонкости и могу соврать.

PS
Кстати, ты зря не слушал Ihor Osov"yak.

Он не зря всё время пытался обратить твоё внимание на
атомы и SetProp
(также функции GlobalAddAtom, GlobalDeleteAtom, GlobalSetProp,
SetProp, GetProp и RemoveProp).

С помощью них можно метод, который я тебе предложил,
сделать гораздо более безопасным.
Можно хранить указатель на объект не через
GWL_USERDATA, а через
SetProp(hWnd, MakeIntAton(MyAtom), Longint(Self) ).
Посмотри, как в модуле Controls реализована ф-я FindControl.
(а мне уже пора бежать - ближняя проходная закрывается)



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2003.06.02;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.56 MB
Время: 0.014 c
1-2913
iVaaL
2003-05-23 06:45
2003.06.02
Компонент ListView


14-3140
Jey
2003-05-14 14:30
2003.06.02
Подскажите пожалуйста хороший форум по 1С


1-2972
Kreo
2003-05-19 20:27
2003.06.02
Fast Report & StringGrid Как???


3-2762
saff
2003-05-13 11:40
2003.06.02
SQL


11-2838
AlbertHakimov
2002-09-07 15:50
2003.06.02
Своиство Align на компоненте Panel-ь





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский